@@ -105,9 +105,9 @@ data class WhiteDnsSettings(
105105 val downloadCompression : Int = 2 ,
106106 val baseEncodeData : Boolean = false ,
107107 val minUploadMtu : String = " 40" ,
108- val minDownloadMtu : String = " 100 " ,
109- val maxUploadMtu : String = " 64 " ,
110- val maxDownloadMtu : String = " 140 " ,
108+ val minDownloadMtu : String = " 300 " ,
109+ val maxUploadMtu : String = " 140 " ,
110+ val maxDownloadMtu : String = " 3000 " ,
111111 val mtuTestRetriesResolvers : String = " 3" ,
112112 val mtuTestTimeoutResolvers : String = " 2.0" ,
113113 val mtuTestParallelismResolvers : String = " 100" ,
@@ -124,6 +124,8 @@ data class WhiteDnsSettings(
124124 val streamQueueInitialCapacity : String = " 128" ,
125125 val orphanQueueInitialCapacity : String = " 32" ,
126126 val dnsResponseFragmentStoreCapacity : String = " 256" ,
127+ val maxActiveStreams : String = " 2048" ,
128+ val localHandshakeTimeoutSeconds : String = " 5.0" ,
127129 val socksUdpAssociateReadTimeoutSeconds : String = " 30.0" ,
128130 val clientTerminalStreamRetentionSeconds : String = " 45.0" ,
129131 val clientCancelledSetupRetentionSeconds : String = " 120.0" ,
@@ -182,6 +184,8 @@ data class ResolvedWhiteDnsSettings(
182184 val streamQueueInitialCapacity : Int ,
183185 val orphanQueueInitialCapacity : Int ,
184186 val dnsResponseFragmentStoreCapacity : Int ,
187+ val maxActiveStreams : Int ,
188+ val localHandshakeTimeoutSeconds : Double ,
185189 val socksUdpAssociateReadTimeoutSeconds : Double ,
186190 val clientTerminalStreamRetentionSeconds : Double ,
187191 val clientCancelledSetupRetentionSeconds : Double ,
@@ -247,6 +251,19 @@ data class ConnectionProgressState(
247251 }
248252}
249253
254+ object ConnectionVerificationStatus {
255+ const val Idle = " idle"
256+ const val Checking = " checking"
257+ const val Verified = " verified"
258+ const val Failed = " failed"
259+ }
260+
261+ data class ConnectionVerificationState (
262+ val status : String = ConnectionVerificationStatus .Idle ,
263+ val message : String = " " ,
264+ val checkedAtMillis : Long = 0 ,
265+ )
266+
250267data class WhiteDnsUiState (
251268 val connectionStatus : ConnectionStatus = ConnectionStatus .DISCONNECTED ,
252269 val settings : WhiteDnsSettings = WhiteDnsSettings (),
@@ -259,6 +276,7 @@ data class WhiteDnsUiState(
259276 val connectionStats : ConnectionStats = ConnectionStats (),
260277 val resolverRuntimeState : ResolverRuntimeState = ResolverRuntimeState (),
261278 val connectionProgress : ConnectionProgressState = ConnectionProgressState (),
279+ val connectionVerification : ConnectionVerificationState = ConnectionVerificationState (),
262280)
263281
264282object WhiteDnsRuntimeProxy {
@@ -694,6 +712,8 @@ fun WhiteDnsSettings.resetAdvancedSettings(): WhiteDnsSettings {
694712 streamQueueInitialCapacity = defaults.streamQueueInitialCapacity,
695713 orphanQueueInitialCapacity = defaults.orphanQueueInitialCapacity,
696714 dnsResponseFragmentStoreCapacity = defaults.dnsResponseFragmentStoreCapacity,
715+ maxActiveStreams = defaults.maxActiveStreams,
716+ localHandshakeTimeoutSeconds = defaults.localHandshakeTimeoutSeconds,
697717 socksUdpAssociateReadTimeoutSeconds = defaults.socksUdpAssociateReadTimeoutSeconds,
698718 clientTerminalStreamRetentionSeconds = defaults.clientTerminalStreamRetentionSeconds,
699719 clientCancelledSetupRetentionSeconds = defaults.clientCancelledSetupRetentionSeconds,
@@ -740,13 +760,29 @@ private fun normalizeResolverText(raw: String): String {
740760}
741761
742762private fun resolverTextTokens (raw : String ): Sequence <String > {
743- return raw
763+ val lines = raw
744764 .replace(" \r\n " , " \n " )
745765 .replace(' \r ' , ' \n ' )
746766 .lineSequence()
747767 .map(String ::trim)
748768 .filter { it.isNotEmpty() && ! it.startsWith(" #" ) }
749- .flatMap { line -> line.split(' ,' , ' ;' ).asSequence() }
769+ .toList()
770+
771+ val separators = if (detectResolverTextEntryType(lines) == ResolverTextEntryType .CommaSeparated ) {
772+ charArrayOf(' ,' , ' ;' )
773+ } else {
774+ charArrayOf()
775+ }
776+
777+ return lines
778+ .asSequence()
779+ .flatMap { line ->
780+ if (separators.isEmpty()) {
781+ sequenceOf(line)
782+ } else {
783+ line.split(* separators).asSequence()
784+ }
785+ }
750786 .map(String ::trim)
751787 .filter { it.isNotEmpty() && ! it.startsWith(" #" ) }
752788}
@@ -757,6 +793,9 @@ private fun normalizeResolverEntry(entry: String): String? {
757793 val hostPort = splitResolverHostPort(entry) ? : return null
758794 val target = normalizeResolverTarget(hostPort.first) ? : return null
759795 val port = hostPort.second.toIntOrNull()?.takeIf { it in 1 .. 65535 } ? : return null
796+ if (port == DefaultResolverPort ) {
797+ return target
798+ }
760799 return if (resolverTargetNeedsBrackets(target)) {
761800 " [$target ]:$port "
762801 } else {
@@ -853,6 +892,21 @@ private fun resolverTargetNeedsBrackets(target: String): Boolean {
853892 return target.substringBefore(' /' ).contains(' :' )
854893}
855894
895+ private fun detectResolverTextEntryType (lines : List <String >): ResolverTextEntryType {
896+ return if (lines.any { it.contains(' ,' ) || it.contains(' ;' ) }) {
897+ ResolverTextEntryType .CommaSeparated
898+ } else {
899+ ResolverTextEntryType .LineSeparated
900+ }
901+ }
902+
903+ private enum class ResolverTextEntryType {
904+ LineSeparated ,
905+ CommaSeparated ,
906+ }
907+
908+ private const val DefaultResolverPort = 53
909+
856910private val ResolverIpv6Chars = Regex (" ^[0-9A-Fa-f:.]+$" )
857911
858912private fun normalizeSplitTunnelMode (raw : String ): String {
@@ -896,12 +950,15 @@ fun WhiteDnsSettings.resolve(): ResolvedWhiteDnsSettings {
896950 return value.coerceIn(minValue, maxValue)
897951 }
898952
899- val resolvers = resolverText
900- .lineSequence()
901- .map(String ::trim)
902- .filter(String ::isNotEmpty)
903- .distinct()
904- .toList()
953+ fun boundedPositiveDouble (raw : String , defaultValue : Double , minValue : Double , maxValue : Double ): Double {
954+ val value = raw.trim().toDoubleOrNull() ? : return defaultValue
955+ if (value <= 0.0 ) {
956+ return defaultValue
957+ }
958+ return value.coerceIn(minValue, maxValue)
959+ }
960+
961+ val resolvers = validateResolverText(resolverText).normalizedResolvers
905962
906963 val resolvedRxTxWorkers = boundedInt(rxTxWorkers, defaultValue = 4 , minValue = 1 , maxValue = 64 )
907964 val resolvedTunnelProcessWorkers = boundedInt(
@@ -916,6 +973,12 @@ fun WhiteDnsSettings.resolve(): ResolvedWhiteDnsSettings {
916973 minValue = 0.1 ,
917974 maxValue = 60.0 ,
918975 )
976+ val resolvedMinUploadMtu = boundedInt(minUploadMtu, defaultValue = 40 , minValue = 1 , maxValue = 65535 )
977+ val resolvedMinDownloadMtu = boundedInt(minDownloadMtu, defaultValue = 300 , minValue = 1 , maxValue = 65535 )
978+ val resolvedMaxUploadMtu = boundedInt(maxUploadMtu, defaultValue = 140 , minValue = 1 , maxValue = 65535 )
979+ .coerceAtLeast(resolvedMinUploadMtu)
980+ val resolvedMaxDownloadMtu = boundedInt(maxDownloadMtu, defaultValue = 3000 , minValue = 1 , maxValue = 65535 )
981+ .coerceAtLeast(resolvedMinDownloadMtu)
919982
920983 return ResolvedWhiteDnsSettings (
921984 connectionMode = when (connectionMode) {
@@ -937,10 +1000,10 @@ fun WhiteDnsSettings.resolve(): ResolvedWhiteDnsSettings {
9371000 uploadCompression = uploadCompression.coerceIn(0 , 3 ),
9381001 downloadCompression = downloadCompression.coerceIn(0 , 3 ),
9391002 baseEncodeData = baseEncodeData,
940- minUploadMtu = boundedInt(minUploadMtu, defaultValue = 40 , minValue = 1 , maxValue = 65535 ) ,
941- minDownloadMtu = boundedInt(minDownloadMtu, defaultValue = 100 , minValue = 1 , maxValue = 65535 ) ,
942- maxUploadMtu = boundedInt(maxUploadMtu, defaultValue = 64 , minValue = 1 , maxValue = 65535 ) ,
943- maxDownloadMtu = boundedInt(maxDownloadMtu, defaultValue = 140 , minValue = 1 , maxValue = 65535 ) ,
1003+ minUploadMtu = resolvedMinUploadMtu ,
1004+ minDownloadMtu = resolvedMinDownloadMtu ,
1005+ maxUploadMtu = resolvedMaxUploadMtu ,
1006+ maxDownloadMtu = resolvedMaxDownloadMtu ,
9441007 mtuTestRetriesResolvers = boundedInt(mtuTestRetriesResolvers, defaultValue = 3 , minValue = 1 , maxValue = 100 ),
9451008 mtuTestTimeoutResolvers = positiveDouble(mtuTestTimeoutResolvers, defaultValue = 2.0 ),
9461009 mtuTestParallelismResolvers = boundedInt(mtuTestParallelismResolvers, defaultValue = 100 , minValue = 1 , maxValue = 1024 ),
@@ -987,6 +1050,18 @@ fun WhiteDnsSettings.resolve(): ResolvedWhiteDnsSettings {
9871050 minValue = 16 ,
9881051 maxValue = 16384 ,
9891052 ),
1053+ maxActiveStreams = boundedInt(
1054+ maxActiveStreams,
1055+ defaultValue = 2048 ,
1056+ minValue = 1 ,
1057+ maxValue = 65535 ,
1058+ ),
1059+ localHandshakeTimeoutSeconds = boundedPositiveDouble(
1060+ localHandshakeTimeoutSeconds,
1061+ defaultValue = 5.0 ,
1062+ minValue = 0.5 ,
1063+ maxValue = 60.0 ,
1064+ ),
9901065 socksUdpAssociateReadTimeoutSeconds = boundedDouble(
9911066 socksUdpAssociateReadTimeoutSeconds,
9921067 defaultValue = 30.0 ,
0 commit comments