Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
1dbb37f9
Unverified
Commit
1dbb37f9
authored
Jan 29, 2019
by
Max Lv
Committed by
GitHub
Jan 29, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2095 from shadowsocks/dnsproxyd
Use dnsproxyd for DNS resolving
parents
a0ae8bf1
27f5c075
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
259 additions
and
103 deletions
+259
-103
core/src/androidTest/java/com/github/shadowsocks/net/SubnetTest.kt
...androidTest/java/com/github/shadowsocks/net/SubnetTest.kt
+2
-2
core/src/main/java/com/github/shadowsocks/Core.kt
core/src/main/java/com/github/shadowsocks/Core.kt
+1
-0
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
+1
-1
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
+8
-3
core/src/main/java/com/github/shadowsocks/bg/GuardedProcessPool.kt
...main/java/com/github/shadowsocks/bg/GuardedProcessPool.kt
+1
-1
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
.../src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
+3
-3
core/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt
...src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt
+2
-1
core/src/main/java/com/github/shadowsocks/bg/TransproxyService.kt
.../main/java/com/github/shadowsocks/bg/TransproxyService.kt
+2
-2
core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
+35
-78
core/src/main/java/com/github/shadowsocks/net/ConcurrentLocalSocketListener.kt
...m/github/shadowsocks/net/ConcurrentLocalSocketListener.kt
+42
-0
core/src/main/java/com/github/shadowsocks/net/DefaultNetworkListener.kt
...java/com/github/shadowsocks/net/DefaultNetworkListener.kt
+135
-0
core/src/main/java/com/github/shadowsocks/net/HttpsTest.kt
core/src/main/java/com/github/shadowsocks/net/HttpsTest.kt
+3
-1
core/src/main/java/com/github/shadowsocks/net/LocalSocketListener.kt
...in/java/com/github/shadowsocks/net/LocalSocketListener.kt
+3
-2
core/src/main/java/com/github/shadowsocks/net/Subnet.kt
core/src/main/java/com/github/shadowsocks/net/Subnet.kt
+2
-1
core/src/main/java/com/github/shadowsocks/net/TcpFastOpen.kt
core/src/main/java/com/github/shadowsocks/net/TcpFastOpen.kt
+1
-1
core/src/main/java/com/github/shadowsocks/preference/DataStore.kt
.../main/java/com/github/shadowsocks/preference/DataStore.kt
+1
-1
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
+2
-2
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
...om/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
+1
-1
mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
...in/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
+11
-2
mobile/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
...e/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
+1
-1
tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
.../java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
+2
-0
No files found.
core/src/androidTest/java/com/github/shadowsocks/
utils
/SubnetTest.kt
→
core/src/androidTest/java/com/github/shadowsocks/
net
/SubnetTest.kt
View file @
1dbb37f9
package
com.github.shadowsocks.
utils
package
com.github.shadowsocks.
net
import
java.net.InetAddress
import
org.junit.Assert
import
org.junit.Assert
import
org.junit.Test
import
org.junit.Test
import
java.net.InetAddress
class
SubnetTest
{
class
SubnetTest
{
@Test
@Test
...
...
core/src/main/java/com/github/shadowsocks/Core.kt
View file @
1dbb37f9
...
@@ -44,6 +44,7 @@ import com.github.shadowsocks.aidl.ShadowsocksConnection
...
@@ -44,6 +44,7 @@ import com.github.shadowsocks.aidl.ShadowsocksConnection
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.net.TcpFastOpen
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.*
import
com.github.shadowsocks.utils.*
import
com.google.firebase.FirebaseApp
import
com.google.firebase.FirebaseApp
...
...
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
View file @
1dbb37f9
...
@@ -25,8 +25,8 @@ import android.util.Log
...
@@ -25,8 +25,8 @@ import android.util.Log
import
androidx.recyclerview.widget.SortedList
import
androidx.recyclerview.widget.SortedList
import
com.crashlytics.android.Crashlytics
import
com.crashlytics.android.Crashlytics
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.net.Subnet
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.Subnet
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.asIterable
import
java.io.File
import
java.io.File
import
java.io.IOException
import
java.io.IOException
...
...
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
View file @
1dbb37f9
...
@@ -42,6 +42,7 @@ import com.github.shadowsocks.utils.printLog
...
@@ -42,6 +42,7 @@ import com.github.shadowsocks.utils.printLog
import
com.google.firebase.analytics.FirebaseAnalytics
import
com.google.firebase.analytics.FirebaseAnalytics
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
java.io.File
import
java.io.File
import
java.net.InetAddress
import
java.net.UnknownHostException
import
java.net.UnknownHostException
import
java.util.*
import
java.util.*
...
@@ -274,6 +275,9 @@ object BaseService {
...
@@ -274,6 +275,9 @@ object BaseService {
}
}
}
}
suspend
fun
preInit
()
{
}
suspend
fun
resolver
(
host
:
String
)
=
InetAddress
.
getByName
(
host
)
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
{
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
{
val
data
=
data
val
data
=
data
if
(
data
.
state
!=
STOPPED
)
return
Service
.
START_NOT_STICKY
if
(
data
.
state
!=
STOPPED
)
return
Service
.
START_NOT_STICKY
...
@@ -306,10 +310,11 @@ object BaseService {
...
@@ -306,10 +310,11 @@ object BaseService {
data
.
changeState
(
CONNECTING
)
data
.
changeState
(
CONNECTING
)
data
.
connectingJob
=
GlobalScope
.
launch
(
Dispatchers
.
Main
)
{
data
.
connectingJob
=
GlobalScope
.
launch
(
Dispatchers
.
Main
)
{
try
{
try
{
proxy
.
init
()
data
.
udpFallback
?.
init
()
killProcesses
()
killProcesses
()
preInit
()
proxy
.
init
(
this
@Interface
::
resolver
)
data
.
udpFallback
?.
init
(
this
@Interface
::
resolver
)
data
.
processes
=
GuardedProcessPool
{
data
.
processes
=
GuardedProcessPool
{
printLog
(
it
)
printLog
(
it
)
data
.
connectingJob
?.
apply
{
runBlocking
{
cancelAndJoin
()
}
}
data
.
connectingJob
?.
apply
{
runBlocking
{
cancelAndJoin
()
}
}
...
...
core/src/main/java/com/github/shadowsocks/bg/GuardedProcessPool.kt
View file @
1dbb37f9
...
@@ -116,7 +116,7 @@ class GuardedProcessPool(private val onFatal: (IOException) -> Unit) : Coroutine
...
@@ -116,7 +116,7 @@ class GuardedProcessPool(private val onFatal: (IOException) -> Unit) : Coroutine
private
val
guards
=
ArrayList
<
Guard
>()
private
val
guards
=
ArrayList
<
Guard
>()
@MainThread
@MainThread
suspend
fun
start
(
cmd
:
List
<
String
>,
onRestartCallback
:
(
suspend
()
->
Unit
)?
=
null
)
{
fun
start
(
cmd
:
List
<
String
>,
onRestartCallback
:
(
suspend
()
->
Unit
)?
=
null
)
{
Crashlytics
.
log
(
Log
.
DEBUG
,
TAG
,
"start process: "
+
Commandline
.
toString
(
cmd
))
Crashlytics
.
log
(
Log
.
DEBUG
,
TAG
,
"start process: "
+
Commandline
.
toString
(
cmd
))
val
guard
=
Guard
(
cmd
)
val
guard
=
Guard
(
cmd
)
guard
.
start
()
guard
.
start
()
...
...
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
View file @
1dbb37f9
...
@@ -52,7 +52,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
...
@@ -52,7 +52,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
private
val
plugin
=
PluginConfiguration
(
profile
.
plugin
?:
""
).
selectedOptions
private
val
plugin
=
PluginConfiguration
(
profile
.
plugin
?:
""
).
selectedOptions
val
pluginPath
by
lazy
{
PluginManager
.
init
(
plugin
)
}
val
pluginPath
by
lazy
{
PluginManager
.
init
(
plugin
)
}
suspend
fun
init
()
{
suspend
fun
init
(
resolver
:
suspend
(
String
)
->
InetAddress
)
{
if
(
profile
.
host
==
"198.199.101.152"
)
{
if
(
profile
.
host
==
"198.199.101.152"
)
{
val
mdg
=
MessageDigest
.
getInstance
(
"SHA-1"
)
val
mdg
=
MessageDigest
.
getInstance
(
"SHA-1"
)
mdg
.
update
(
Core
.
packageInfo
.
signaturesCompat
.
first
().
toByteArray
())
mdg
.
update
(
Core
.
packageInfo
.
signaturesCompat
.
first
().
toByteArray
())
...
@@ -84,7 +84,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
...
@@ -84,7 +84,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
// it's hard to resolve DNS on a specific interface so we'll do it here
// it's hard to resolve DNS on a specific interface so we'll do it here
if
(
profile
.
host
.
parseNumericAddress
()
==
null
)
profile
.
host
=
withTimeout
(
10_000
)
{
if
(
profile
.
host
.
parseNumericAddress
()
==
null
)
profile
.
host
=
withTimeout
(
10_000
)
{
withContext
(
Dispatchers
.
IO
)
{
InetAddress
.
getByName
(
profile
.
host
).
hostAddress
}
withContext
(
Dispatchers
.
IO
)
{
resolver
(
profile
.
host
).
hostAddress
}
}
?:
throw
UnknownHostException
()
}
?:
throw
UnknownHostException
()
}
}
...
@@ -92,7 +92,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
...
@@ -92,7 +92,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
* Sensitive shadowsocks configuration file requires extra protection. It may be stored in encrypted storage or
* Sensitive shadowsocks configuration file requires extra protection. It may be stored in encrypted storage or
* device storage, depending on which is currently available.
* device storage, depending on which is currently available.
*/
*/
suspend
fun
start
(
service
:
BaseService
.
Interface
,
stat
:
File
,
configFile
:
File
,
extraFlag
:
String
?
=
null
)
{
fun
start
(
service
:
BaseService
.
Interface
,
stat
:
File
,
configFile
:
File
,
extraFlag
:
String
?
=
null
)
{
trafficMonitor
=
TrafficMonitor
(
stat
)
trafficMonitor
=
TrafficMonitor
(
stat
)
this
.
configFile
=
configFile
this
.
configFile
=
configFile
...
...
core/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt
View file @
1dbb37f9
...
@@ -23,6 +23,7 @@ package com.github.shadowsocks.bg
...
@@ -23,6 +23,7 @@ package com.github.shadowsocks.bg
import
android.net.LocalSocket
import
android.net.LocalSocket
import
android.os.SystemClock
import
android.os.SystemClock
import
com.github.shadowsocks.aidl.TrafficStats
import
com.github.shadowsocks.aidl.TrafficStats
import
com.github.shadowsocks.net.LocalSocketListener
import
java.io.File
import
java.io.File
import
java.io.IOException
import
java.io.IOException
import
java.nio.ByteBuffer
import
java.nio.ByteBuffer
...
@@ -30,7 +31,7 @@ import java.nio.ByteOrder
...
@@ -30,7 +31,7 @@ import java.nio.ByteOrder
class
TrafficMonitor
(
statFile
:
File
)
:
AutoCloseable
{
class
TrafficMonitor
(
statFile
:
File
)
:
AutoCloseable
{
private
val
thread
=
object
:
LocalSocketListener
(
"TrafficMonitor"
,
statFile
)
{
private
val
thread
=
object
:
LocalSocketListener
(
"TrafficMonitor"
,
statFile
)
{
override
fun
accept
(
socket
:
LocalSocket
)
=
socket
.
use
{
override
fun
accept
Internal
(
socket
:
LocalSocket
)
{
val
buffer
=
ByteArray
(
16
)
val
buffer
=
ByteArray
(
16
)
if
(
socket
.
inputStream
.
read
(
buffer
)
!=
16
)
throw
IOException
(
"Unexpected traffic stat length"
)
if
(
socket
.
inputStream
.
read
(
buffer
)
!=
16
)
throw
IOException
(
"Unexpected traffic stat length"
)
val
stat
=
ByteBuffer
.
wrap
(
buffer
).
order
(
ByteOrder
.
LITTLE_ENDIAN
)
val
stat
=
ByteBuffer
.
wrap
(
buffer
).
order
(
ByteOrder
.
LITTLE_ENDIAN
)
...
...
core/src/main/java/com/github/shadowsocks/bg/TransproxyService.kt
View file @
1dbb37f9
...
@@ -36,7 +36,7 @@ class TransproxyService : Service(), LocalDnsService.Interface {
...
@@ -36,7 +36,7 @@ class TransproxyService : Service(), LocalDnsService.Interface {
override
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
=
override
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
=
super
<
LocalDnsService
.
Interface
>.
onStartCommand
(
intent
,
flags
,
startId
)
super
<
LocalDnsService
.
Interface
>.
onStartCommand
(
intent
,
flags
,
startId
)
private
suspend
fun
startDNSTunnel
()
{
private
fun
startDNSTunnel
()
{
val
proxy
=
data
.
proxy
!!
val
proxy
=
data
.
proxy
!!
val
cmd
=
arrayListOf
(
File
(
applicationInfo
.
nativeLibraryDir
,
Executable
.
SS_TUNNEL
).
absolutePath
,
val
cmd
=
arrayListOf
(
File
(
applicationInfo
.
nativeLibraryDir
,
Executable
.
SS_TUNNEL
).
absolutePath
,
"-t"
,
"10"
,
"-t"
,
"10"
,
...
@@ -50,7 +50,7 @@ class TransproxyService : Service(), LocalDnsService.Interface {
...
@@ -50,7 +50,7 @@ class TransproxyService : Service(), LocalDnsService.Interface {
data
.
processes
!!
.
start
(
cmd
)
data
.
processes
!!
.
start
(
cmd
)
}
}
private
suspend
fun
startRedsocksDaemon
()
{
private
fun
startRedsocksDaemon
()
{
File
(
Core
.
deviceStorage
.
noBackupFilesDir
,
"redsocks.conf"
).
writeText
(
"""base {
File
(
Core
.
deviceStorage
.
noBackupFilesDir
,
"redsocks.conf"
).
writeText
(
"""base {
log_debug = off;
log_debug = off;
log_info = off;
log_info = off;
...
...
core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
View file @
1dbb37f9
...
@@ -20,26 +20,28 @@
...
@@ -20,26 +20,28 @@
package
com.github.shadowsocks.bg
package
com.github.shadowsocks.bg
import
android.annotation.TargetApi
import
android.app.Service
import
android.app.Service
import
android.content.Intent
import
android.content.Intent
import
android.content.pm.PackageManager
import
android.content.pm.PackageManager
import
android.net.*
import
android.net.LocalSocket
import
android.net.LocalSocketAddress
import
android.net.Network
import
android.os.Build
import
android.os.Build
import
android.os.ParcelFileDescriptor
import
android.os.ParcelFileDescriptor
import
android.system.ErrnoException
import
android.system.ErrnoException
import
android.system.Os
import
android.system.Os
import
androidx.core.content.getSystemService
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.VpnRequestActivity
import
com.github.shadowsocks.VpnRequestActivity
import
com.github.shadowsocks.acl.Acl
import
com.github.shadowsocks.acl.Acl
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.net.ConcurrentLocalSocketListener
import
com.github.shadowsocks.net.DefaultNetworkListener
import
com.github.shadowsocks.net.Subnet
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Subnet
import
com.github.shadowsocks.utils.parseNumericAddress
import
com.github.shadowsocks.utils.parseNumericAddress
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
kotlinx.coroutines.
*
import
kotlinx.coroutines.
delay
import
java.io.Closeable
import
java.io.Closeable
import
java.io.File
import
java.io.File
import
java.io.FileDescriptor
import
java.io.FileDescriptor
...
@@ -58,60 +60,32 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
...
@@ -58,60 +60,32 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
* https://android.googlesource.com/platform/prebuilts/runtime/+/94fec32/appcompat/hiddenapi-light-greylist.txt#9466
* https://android.googlesource.com/platform/prebuilts/runtime/+/94fec32/appcompat/hiddenapi-light-greylist.txt#9466
*/
*/
private
val
getInt
:
Method
=
FileDescriptor
::
class
.
java
.
getDeclaredMethod
(
"getInt$"
)
private
val
getInt
:
Method
=
FileDescriptor
::
class
.
java
.
getDeclaredMethod
(
"getInt$"
)
/**
* Unfortunately registerDefaultNetworkCallback is going to return VPN interface since Android P DP1:
* https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
*
* This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
* satisfies default network capabilities but only THE default network. Unfortunately we need to have
* android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
*
* Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
*/
private
val
defaultNetworkRequest
=
NetworkRequest
.
Builder
()
.
addCapability
(
NetworkCapabilities
.
NET_CAPABILITY_INTERNET
)
.
addCapability
(
NetworkCapabilities
.
NET_CAPABILITY_NOT_RESTRICTED
)
.
build
()
}
}
class
CloseableFd
(
val
fd
:
FileDescriptor
)
:
Closeable
{
class
CloseableFd
(
val
fd
:
FileDescriptor
)
:
Closeable
{
override
fun
close
()
=
Os
.
close
(
fd
)
override
fun
close
()
=
Os
.
close
(
fd
)
}
}
private
inner
class
ProtectWorker
:
private
inner
class
ProtectWorker
:
ConcurrentLocalSocketListener
(
"ShadowsocksVpnThread"
,
LocalSocketListener
(
"ShadowsocksVpnThread"
,
File
(
Core
.
deviceStorage
.
noBackupFilesDir
,
"protect_path"
)),
File
(
Core
.
deviceStorage
.
noBackupFilesDir
,
"protect_path"
))
{
CoroutineScope
{
override
fun
acceptInternal
(
socket
:
LocalSocket
)
{
private
val
job
=
SupervisorJob
()
socket
.
inputStream
.
read
()
override
val
coroutineContext
get
()
=
Dispatchers
.
IO
+
job
+
CoroutineExceptionHandler
{
_
,
t
->
printLog
(
t
)
}
val
fd
=
socket
.
ancillaryFileDescriptors
!!
.
single
()
!!
CloseableFd
(
fd
).
use
{
override
fun
accept
(
socket
:
LocalSocket
)
{
socket
.
outputStream
.
write
(
if
(
underlyingNetwork
.
let
{
network
->
launch
{
if
(
network
!=
null
&&
Build
.
VERSION
.
SDK_INT
>=
23
)
try
{
socket
.
use
{
network
.
bindSocket
(
fd
)
socket
.
inputStream
.
read
()
true
val
fd
=
socket
.
ancillaryFileDescriptors
!!
.
single
()
!!
}
catch
(
e
:
IOException
)
{
CloseableFd
(
fd
).
use
{
// suppress ENONET (Machine is not on the network)
socket
.
outputStream
.
write
(
if
(
underlyingNetwork
.
let
{
network
->
if
((
e
.
cause
as
?
ErrnoException
)
?.
errno
!=
64
)
printLog
(
e
)
if
(
network
!=
null
&&
Build
.
VERSION
.
SDK_INT
>=
23
)
try
{
false
network
.
bindSocket
(
fd
)
}
else
protect
(
getInt
.
invoke
(
fd
)
as
Int
)
true
})
0
else
1
)
}
catch
(
e
:
IOException
)
{
// suppress ENONET (Machine is not on the network)
if
((
e
.
cause
as
?
ErrnoException
)
?.
errno
!=
64
)
printLog
(
e
)
false
}
else
protect
(
getInt
.
invoke
(
fd
)
as
Int
)
})
0
else
1
)
}
}
}
}
}
}
suspend
fun
shutdown
()
{
job
.
cancel
()
close
()
job
.
join
()
}
}
}
inner
class
NullConnectionException
:
NullPointerException
()
{
inner
class
NullConnectionException
:
NullPointerException
()
{
override
fun
getLocalizedMessage
()
=
getString
(
R
.
string
.
reboot_required
)
override
fun
getLocalizedMessage
()
=
getString
(
R
.
string
.
reboot_required
)
}
}
...
@@ -123,28 +97,13 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
...
@@ -123,28 +97,13 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
private
var
conn
:
ParcelFileDescriptor
?
=
null
private
var
conn
:
ParcelFileDescriptor
?
=
null
private
var
worker
:
ProtectWorker
?
=
null
private
var
worker
:
ProtectWorker
?
=
null
private
var
active
=
false
private
var
underlyingNetwork
:
Network
?
=
null
private
var
underlyingNetwork
:
Network
?
=
null
@TargetApi
(
24
)
set
(
value
)
{
set
(
value
)
{
setUnderlyingNetworks
(
if
(
value
==
null
)
null
else
arrayOf
(
value
))
field
=
value
field
=
value
if
(
active
&&
Build
.
VERSION
.
SDK_INT
>=
22
)
setUnderlyingNetworks
(
underlyingNetworks
)
}
}
private
val
underlyingNetworks
=
underlyingNetwork
?.
let
{
arrayOf
(
it
)
}
private
val
connectivity
by
lazy
{
getSystemService
<
ConnectivityManager
>()
!!
}
@TargetApi
(
24
)
private
val
defaultNetworkCallback
=
object
:
ConnectivityManager
.
NetworkCallback
()
{
override
fun
onAvailable
(
network
:
Network
)
{
underlyingNetwork
=
network
}
override
fun
onCapabilitiesChanged
(
network
:
Network
,
networkCapabilities
:
NetworkCapabilities
?)
{
// it's a good idea to refresh capabilities
underlyingNetwork
=
network
}
override
fun
onLost
(
network
:
Network
)
{
underlyingNetwork
=
null
}
}
private
var
listeningForDefaultNetwork
=
false
override
fun
onBind
(
intent
:
Intent
)
=
when
(
intent
.
action
)
{
override
fun
onBind
(
intent
:
Intent
)
=
when
(
intent
.
action
)
{
SERVICE_INTERFACE
->
super
<
BaseVpnService
>.
onBind
(
intent
)
SERVICE_INTERFACE
->
super
<
BaseVpnService
>.
onBind
(
intent
)
...
@@ -154,10 +113,8 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
...
@@ -154,10 +113,8 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override
fun
onRevoke
()
=
stopRunner
()
override
fun
onRevoke
()
=
stopRunner
()
override
suspend
fun
killProcesses
()
{
override
suspend
fun
killProcesses
()
{
if
(
listeningForDefaultNetwork
)
{
active
=
false
connectivity
.
unregisterNetworkCallback
(
defaultNetworkCallback
)
DefaultNetworkListener
.
stop
(
this
)
listeningForDefaultNetwork
=
false
}
worker
?.
shutdown
()
worker
?.
shutdown
()
worker
=
null
worker
=
null
super
.
killProcesses
()
super
.
killProcesses
()
...
@@ -175,6 +132,9 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
...
@@ -175,6 +132,9 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
return
Service
.
START_NOT_STICKY
return
Service
.
START_NOT_STICKY
}
}
override
suspend
fun
preInit
()
=
DefaultNetworkListener
.
start
(
this
)
{
underlyingNetwork
=
it
}
override
suspend
fun
resolver
(
host
:
String
)
=
DefaultNetworkListener
.
get
().
getByName
(
host
)
override
suspend
fun
startProcesses
()
{
override
suspend
fun
startProcesses
()
{
worker
=
ProtectWorker
().
apply
{
start
()
}
worker
=
ProtectWorker
().
apply
{
start
()
}
...
@@ -230,16 +190,13 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
...
@@ -230,16 +190,13 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
}
}
}
}
active
=
true
// possible race condition here?
if
(
Build
.
VERSION
.
SDK_INT
>=
22
)
builder
.
setUnderlyingNetworks
(
underlyingNetworks
)
val
conn
=
builder
.
establish
()
?:
throw
NullConnectionException
()
val
conn
=
builder
.
establish
()
?:
throw
NullConnectionException
()
this
.
conn
=
conn
this
.
conn
=
conn
val
fd
=
conn
.
fd
val
fd
=
conn
.
fd
if
(
Build
.
VERSION
.
SDK_INT
>=
24
)
{
// we want REQUEST here instead of LISTEN
connectivity
.
requestNetwork
(
defaultNetworkRequest
,
defaultNetworkCallback
)
listeningForDefaultNetwork
=
true
}
val
cmd
=
arrayListOf
(
File
(
applicationInfo
.
nativeLibraryDir
,
Executable
.
TUN2SOCKS
).
absolutePath
,
val
cmd
=
arrayListOf
(
File
(
applicationInfo
.
nativeLibraryDir
,
Executable
.
TUN2SOCKS
).
absolutePath
,
"--netif-ipaddr"
,
PRIVATE_VLAN
.
format
(
Locale
.
ENGLISH
,
"2"
),
"--netif-ipaddr"
,
PRIVATE_VLAN
.
format
(
Locale
.
ENGLISH
,
"2"
),
"--netif-netmask"
,
"255.255.255.0"
,
"--netif-netmask"
,
"255.255.255.0"
,
...
...
core/src/main/java/com/github/shadowsocks/net/ConcurrentLocalSocketListener.kt
0 → 100644
View file @
1dbb37f9
/*******************************************************************************
* *
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* 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/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.net
import
android.net.LocalSocket
import
com.github.shadowsocks.utils.printLog
import
kotlinx.coroutines.*
import
java.io.File
abstract
class
ConcurrentLocalSocketListener
(
name
:
String
,
socketFile
:
File
)
:
LocalSocketListener
(
name
,
socketFile
),
CoroutineScope
{
private
val
job
=
SupervisorJob
()
override
val
coroutineContext
get
()
=
Dispatchers
.
IO
+
job
+
CoroutineExceptionHandler
{
_
,
t
->
printLog
(
t
)
}
override
fun
accept
(
socket
:
LocalSocket
)
{
launch
{
super
.
accept
(
socket
)
}
}
suspend
fun
shutdown
()
{
job
.
cancel
()
close
()
job
.
join
()
}
}
core/src/main/java/com/github/shadowsocks/net/DefaultNetworkListener.kt
0 → 100644
View file @
1dbb37f9
/*******************************************************************************
* *
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* 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/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.net
import
android.annotation.TargetApi
import
android.net.ConnectivityManager
import
android.net.Network
import
android.net.NetworkCapabilities
import
android.net.NetworkRequest
import
android.os.Build
import
android.widget.Toast
import
androidx.core.content.getSystemService
import
com.crashlytics.android.Crashlytics
import
com.github.shadowsocks.Core.app
import
kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.channels.actor
import
kotlinx.coroutines.runBlocking
import
java.net.UnknownHostException
object
DefaultNetworkListener
:
CoroutineScope
{
override
val
coroutineContext
get
()
=
Dispatchers
.
Default
private
sealed
class
NetworkMessage
{
class
Start
(
val
key
:
Any
,
val
listener
:
(
Network
?)
->
Unit
)
:
NetworkMessage
()
class
Get
:
NetworkMessage
()
{
val
response
=
CompletableDeferred
<
Network
>()
}
class
Stop
(
val
key
:
Any
)
:
NetworkMessage
()
class
Put
(
val
network
:
Network
)
:
NetworkMessage
()
class
Update
(
val
network
:
Network
)
:
NetworkMessage
()
class
Lost
(
val
network
:
Network
)
:
NetworkMessage
()
}
private
val
networkActor
=
actor
<
NetworkMessage
>
{
val
listeners
=
mutableMapOf
<
Any
,
(
Network
?)
->
Unit
>()
var
network
:
Network
?
=
null
val
pendingRequests
=
arrayListOf
<
NetworkMessage
.
Get
>()
for
(
message
in
channel
)
when
(
message
)
{
is
NetworkMessage
.
Start
->
{
if
(
listeners
.
isEmpty
())
registerDefaultNetworkListener
()
listeners
[
message
.
key
]
=
message
.
listener
if
(
network
!=
null
)
message
.
listener
(
network
)
}
is
NetworkMessage
.
Get
->
{
check
(
listeners
.
isNotEmpty
())
{
"Getting network without any listeners is not supported"
}
if
(
network
==
null
)
pendingRequests
+=
message
else
message
.
response
.
complete
(
network
)
}
is
NetworkMessage
.
Stop
->
{
if
(!
listeners
.
isEmpty
()
&&
// was not empty
listeners
.
remove
(
message
.
key
)
!=
null
&&
listeners
.
isEmpty
())
unregisterDefaultNetworkListener
()
}
is
NetworkMessage
.
Put
->
{
network
=
message
.
network
pendingRequests
.
forEach
{
it
.
response
.
complete
(
message
.
network
)
}
pendingRequests
.
clear
()
listeners
.
values
.
forEach
{
it
(
network
)
}
}
is
NetworkMessage
.
Update
->
if
(
network
==
message
.
network
)
listeners
.
values
.
forEach
{
it
(
network
)
}
is
NetworkMessage
.
Lost
->
if
(
network
==
message
.
network
)
{
network
=
null
listeners
.
values
.
forEach
{
it
(
null
)
}
}
}
}
suspend
fun
start
(
key
:
Any
,
listener
:
(
Network
?)
->
Unit
)
=
networkActor
.
send
(
NetworkMessage
.
Start
(
key
,
listener
))
suspend
fun
get
()
=
if
(
fallback
)
@TargetApi
(
23
)
{
connectivity
.
activeNetwork
?:
throw
UnknownHostException
()
// failed to listen, return current if available
}
else
NetworkMessage
.
Get
().
run
{
networkActor
.
send
(
this
)
response
.
await
()
}
suspend
fun
stop
(
key
:
Any
)
=
networkActor
.
send
(
NetworkMessage
.
Stop
(
key
))
// NB: this runs in ConnectivityThread, and this behavior cannot be changed until API 26
private
object
Callback
:
ConnectivityManager
.
NetworkCallback
()
{
override
fun
onAvailable
(
network
:
Network
)
=
runBlocking
{
networkActor
.
send
(
NetworkMessage
.
Put
(
network
))
}
override
fun
onCapabilitiesChanged
(
network
:
Network
,
networkCapabilities
:
NetworkCapabilities
?)
{
// it's a good idea to refresh capabilities
runBlocking
{
networkActor
.
send
(
NetworkMessage
.
Update
(
network
))
}
}
override
fun
onLost
(
network
:
Network
)
=
runBlocking
{
networkActor
.
send
(
NetworkMessage
.
Lost
(
network
))
}
}
private
var
fallback
=
false
private
val
connectivity
=
app
.
getSystemService
<
ConnectivityManager
>()
!!
private
val
defaultNetworkRequest
=
NetworkRequest
.
Builder
()
.
addCapability
(
NetworkCapabilities
.
NET_CAPABILITY_INTERNET
)
.
addCapability
(
NetworkCapabilities
.
NET_CAPABILITY_NOT_RESTRICTED
)
.
build
()
/**
* Unfortunately registerDefaultNetworkCallback is going to return VPN interface since Android P DP1:
* https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
*
* This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
* satisfies default network capabilities but only THE default network. Unfortunately, we need to have
* android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
*
* Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
*/
private
fun
registerDefaultNetworkListener
()
{
if
(
Build
.
VERSION
.
SDK_INT
in
24
..
27
)
@TargetApi
(
24
)
{
connectivity
.
registerDefaultNetworkCallback
(
Callback
)
}
else
try
{
fallback
=
false
// we want REQUEST here instead of LISTEN
connectivity
.
requestNetwork
(
defaultNetworkRequest
,
Callback
)
}
catch
(
e
:
SecurityException
)
{
// known bug: https://stackoverflow.com/a/33509180/2245107
if
(
Build
.
VERSION
.
SDK_INT
!=
23
)
Crashlytics
.
logException
(
e
)
fallback
=
true
}
}
private
fun
unregisterDefaultNetworkListener
()
=
connectivity
.
unregisterNetworkCallback
(
Callback
)
}
core/src/main/java/com/github/shadowsocks/
utils
/HttpsTest.kt
→
core/src/main/java/com/github/shadowsocks/
net
/HttpsTest.kt
View file @
1dbb37f9
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
* *
* *
*******************************************************************************/
*******************************************************************************/
package
com.github.shadowsocks.
utils
package
com.github.shadowsocks.
net
import
android.os.SystemClock
import
android.os.SystemClock
import
androidx.lifecycle.MutableLiveData
import
androidx.lifecycle.MutableLiveData
...
@@ -28,6 +28,8 @@ import com.github.shadowsocks.Core.app
...
@@ -28,6 +28,8 @@ import com.github.shadowsocks.Core.app
import
com.github.shadowsocks.acl.Acl
import
com.github.shadowsocks.acl.Acl
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.core.R
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.responseLength
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
java.io.IOException
import
java.io.IOException
import
java.net.HttpURLConnection
import
java.net.HttpURLConnection
...
...
core/src/main/java/com/github/shadowsocks/
bg
/LocalSocketListener.kt
→
core/src/main/java/com/github/shadowsocks/
net
/LocalSocketListener.kt
View file @
1dbb37f9
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
* *
* *
*******************************************************************************/
*******************************************************************************/
package
com.github.shadowsocks.
bg
package
com.github.shadowsocks.
net
import
android.net.LocalServerSocket
import
android.net.LocalServerSocket
import
android.net.LocalSocket
import
android.net.LocalSocket
...
@@ -42,7 +42,8 @@ abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name
...
@@ -42,7 +42,8 @@ abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name
/**
/**
* Inherited class do not need to close input/output streams as they will be closed automatically.
* Inherited class do not need to close input/output streams as they will be closed automatically.
*/
*/
protected
abstract
fun
accept
(
socket
:
LocalSocket
)
protected
open
fun
accept
(
socket
:
LocalSocket
)
=
socket
.
use
{
acceptInternal
(
socket
)
}
protected
abstract
fun
acceptInternal
(
socket
:
LocalSocket
)
final
override
fun
run
()
=
localSocket
.
use
{
final
override
fun
run
()
=
localSocket
.
use
{
while
(
running
)
{
while
(
running
)
{
try
{
try
{
...
...
core/src/main/java/com/github/shadowsocks/
utils
/Subnet.kt
→
core/src/main/java/com/github/shadowsocks/
net
/Subnet.kt
View file @
1dbb37f9
...
@@ -18,8 +18,9 @@
...
@@ -18,8 +18,9 @@
* *
* *
*******************************************************************************/
*******************************************************************************/
package
com.github.shadowsocks.
utils
package
com.github.shadowsocks.
net
import
com.github.shadowsocks.utils.parseNumericAddress
import
java.net.InetAddress
import
java.net.InetAddress
import
java.util.*
import
java.util.*
...
...
core/src/main/java/com/github/shadowsocks/
utils
/TcpFastOpen.kt
→
core/src/main/java/com/github/shadowsocks/
net
/TcpFastOpen.kt
View file @
1dbb37f9
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
* *
* *
*******************************************************************************/
*******************************************************************************/
package
com.github.shadowsocks.
utils
package
com.github.shadowsocks.
net
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.withTimeoutOrNull
import
kotlinx.coroutines.withTimeoutOrNull
...
...
core/src/main/java/com/github/shadowsocks/preference/DataStore.kt
View file @
1dbb37f9
...
@@ -27,7 +27,7 @@ import com.github.shadowsocks.database.PrivateDatabase
...
@@ -27,7 +27,7 @@ import com.github.shadowsocks.database.PrivateDatabase
import
com.github.shadowsocks.database.PublicDatabase
import
com.github.shadowsocks.database.PublicDatabase
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.
utils
.TcpFastOpen
import
com.github.shadowsocks.
net
.TcpFastOpen
import
com.github.shadowsocks.utils.parsePort
import
com.github.shadowsocks.utils.parsePort
import
java.net.NetworkInterface
import
java.net.NetworkInterface
import
java.net.SocketException
import
java.net.SocketException
...
...
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
View file @
1dbb37f9
...
@@ -49,8 +49,8 @@ private val parseNumericAddress by lazy {
...
@@ -49,8 +49,8 @@ private val parseNumericAddress by lazy {
*
*
* Bug: https://issuetracker.google.com/issues/123456213
* Bug: https://issuetracker.google.com/issues/123456213
*/
*/
fun
String
?.
parseNumericAddress
():
InetAddress
?
=
Os
.
inet_pton
(
OsConstants
.
AF_INET
,
this
)
?:
fun
String
?.
parseNumericAddress
():
InetAddress
?
=
Os
.
inet_pton
(
OsConstants
.
AF_INET
,
this
)
Os
.
inet_pton
(
OsConstants
.
AF_INET6
,
this
)
?.
let
{
parseNumericAddress
.
invoke
(
null
,
this
)
as
InetAddress
}
?:
Os
.
inet_pton
(
OsConstants
.
AF_INET6
,
this
)
?.
let
{
parseNumericAddress
.
invoke
(
null
,
this
)
as
InetAddress
}
fun
parsePort
(
str
:
String
?,
default
:
Int
,
min
:
Int
=
1025
):
Int
{
fun
parsePort
(
str
:
String
?,
default
:
Int
,
min
:
Int
=
1025
):
Int
{
val
value
=
str
?.
toIntOrNull
()
?:
default
val
value
=
str
?.
toIntOrNull
()
?:
default
...
...
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
View file @
1dbb37f9
...
@@ -28,7 +28,7 @@ import com.github.shadowsocks.bg.BaseService
...
@@ -28,7 +28,7 @@ import com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.
utils
.TcpFastOpen
import
com.github.shadowsocks.
net
.TcpFastOpen
import
com.github.shadowsocks.utils.remove
import
com.github.shadowsocks.utils.remove
import
com.takisoft.preferencex.PreferenceFragmentCompat
import
com.takisoft.preferencex.PreferenceFragmentCompat
...
...
mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
View file @
1dbb37f9
...
@@ -42,7 +42,7 @@ import com.github.shadowsocks.MainActivity
...
@@ -42,7 +42,7 @@ import com.github.shadowsocks.MainActivity
import
com.github.shadowsocks.R
import
com.github.shadowsocks.R
import
com.github.shadowsocks.ToolbarFragment
import
com.github.shadowsocks.ToolbarFragment
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.
utils
.Subnet
import
com.github.shadowsocks.
net
.Subnet
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.resolveResourceId
import
com.github.shadowsocks.utils.resolveResourceId
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.github.shadowsocks.widget.UndoSnackbarManager
...
@@ -51,6 +51,7 @@ import java.net.IDN
...
@@ -51,6 +51,7 @@ import java.net.IDN
import
java.net.MalformedURLException
import
java.net.MalformedURLException
import
java.net.URL
import
java.net.URL
import
java.util.*
import
java.util.*
import
java.util.regex.PatternSyntaxException
class
CustomRulesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
,
ActionMode
.
Callback
{
class
CustomRulesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
,
ActionMode
.
Callback
{
companion
object
{
companion
object
{
...
@@ -128,7 +129,15 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -128,7 +129,15 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
private
fun
validate
(
template
:
Int
=
templateSelector
.
selectedItemPosition
,
value
:
Editable
=
editText
.
text
)
{
private
fun
validate
(
template
:
Int
=
templateSelector
.
selectedItemPosition
,
value
:
Editable
=
editText
.
text
)
{
var
message
=
""
var
message
=
""
positive
.
isEnabled
=
when
(
Template
.
values
()[
template
])
{
positive
.
isEnabled
=
when
(
Template
.
values
()[
template
])
{
Template
.
Generic
->
value
.
isNotEmpty
()
Template
.
Generic
->
value
.
toString
().
run
{
try
{
if
(
Subnet
.
fromString
(
this
)
==
null
)
toPattern
()
true
}
catch
(
e
:
PatternSyntaxException
)
{
message
=
e
.
localizedMessage
false
}
}
Template
.
Domain
->
try
{
Template
.
Domain
->
try
{
IDN
.
toASCII
(
value
.
toString
(),
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
)
IDN
.
toASCII
(
value
.
toString
(),
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
)
true
true
...
...
mobile/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
View file @
1dbb37f9
...
@@ -33,7 +33,7 @@ import androidx.lifecycle.get
...
@@ -33,7 +33,7 @@ import androidx.lifecycle.get
import
com.github.shadowsocks.MainActivity
import
com.github.shadowsocks.MainActivity
import
com.github.shadowsocks.R
import
com.github.shadowsocks.R
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.
utils
.HttpsTest
import
com.github.shadowsocks.
net
.HttpsTest
import
com.google.android.material.bottomappbar.BottomAppBar
import
com.google.android.material.bottomappbar.BottomAppBar
class
StatsBar
@JvmOverloads
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?
=
null
,
class
StatsBar
@JvmOverloads
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?
=
null
,
...
...
tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
View file @
1dbb37f9
...
@@ -50,6 +50,8 @@ import com.github.shadowsocks.bg.BaseService
...
@@ -50,6 +50,8 @@ import com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.Executable
import
com.github.shadowsocks.bg.Executable
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.net.HttpsTest
import
com.github.shadowsocks.net.TcpFastOpen
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import
com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import
com.github.shadowsocks.utils.*
import
com.github.shadowsocks.utils.*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment