Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,25 @@ class MasterDnsVpnService : VpnService() {
"com.android.chrome" // system Chrome on some OEMs
)


internal fun parseConnectTarget(url: String): Pair<String, Int> {
if (url.startsWith("[")) {
val close = url.indexOf("]")
if (close > 0) {
val host = url.substring(1, close)
val portPart = url.substring(close + 1).removePrefix(":")
val port = portPart.toIntOrNull()?.coerceIn(1, 65535) ?: 80
return host to port
}
}
val lastColon = url.lastIndexOf(':')
return if (lastColon > 0) {
val host = url.substring(0, lastColon)
val port = url.substring(lastColon + 1).toIntOrNull()?.coerceIn(1, 65535) ?: 80
host to port
} else {
url to 80
}
}
}

private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
Expand Down Expand Up @@ -122,6 +140,19 @@ class MasterDnsVpnService : VpnService() {
val profileId = intent.getLongExtra(EXTRA_PROFILE_ID, -1)
if (profileId > 0) {
startVpn(profileId)
} else {
val msg = "Invalid profile id: $profileId"
VpnManager.appendLog(msg)
VpnManager.setError(msg)
runCatching {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE)
} else {
@Suppress("DEPRECATION")
stopForeground(true)
}
}
runCatching { stopSelf() }
}
}
ACTION_DISCONNECT -> {
Expand Down Expand Up @@ -979,9 +1010,7 @@ class MasterDnsVpnService : VpnService() {
}

if (method == "CONNECT") {
val hostPort = url.split(":")
val host = hostPort[0]
val port = hostPort.getOrElse(1) { "80" }.toIntOrNull() ?: 80
val (host, port) = parseConnectTarget(url)

output.write("HTTP/1.1 200 Connection Established\r\n\r\n")
output.flush()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -38,8 +39,8 @@ object GlobalSettingsStore {
private val KEY_CUSTOM_DNS_SERVERS = stringPreferencesKey("custom_dns_servers")
private val KEY_FAKE_DNS_ENABLED = booleanPreferencesKey("fake_dns_enabled")
private val KEY_INTERNET_SHARING_ENABLED = booleanPreferencesKey("internet_sharing_enabled")
private val KEY_INTERNET_SHARING_SOCKS_PORT = stringPreferencesKey("internet_sharing_socks_port")
private val KEY_INTERNET_SHARING_HTTP_PORT = stringPreferencesKey("internet_sharing_http_port")
private val KEY_INTERNET_SHARING_SOCKS_PORT = intPreferencesKey("internet_sharing_socks_port_v2")
private val KEY_INTERNET_SHARING_HTTP_PORT = intPreferencesKey("internet_sharing_http_port_v2")
private val KEY_INTERNET_SHARING_USER = stringPreferencesKey("internet_sharing_user")
private val KEY_INTERNET_SHARING_PASS = stringPreferencesKey("internet_sharing_pass")

Expand All @@ -63,8 +64,8 @@ object GlobalSettingsStore {
prefs[KEY_CUSTOM_DNS_SERVERS] = settings.customDnsServers
prefs[KEY_FAKE_DNS_ENABLED] = settings.fakeDnsEnabled
prefs[KEY_INTERNET_SHARING_ENABLED] = settings.internetSharingEnabled
prefs[KEY_INTERNET_SHARING_SOCKS_PORT] = settings.internetSharingSocksPort.toString()
prefs[KEY_INTERNET_SHARING_HTTP_PORT] = settings.internetSharingHttpPort.toString()
prefs[KEY_INTERNET_SHARING_SOCKS_PORT] = settings.internetSharingSocksPort.coerceIn(1, 65535)
prefs[KEY_INTERNET_SHARING_HTTP_PORT] = settings.internetSharingHttpPort.coerceIn(1, 65535)
prefs[KEY_INTERNET_SHARING_USER] = settings.internetSharingUser
prefs[KEY_INTERNET_SHARING_PASS] = settings.internetSharingPass
}
Expand All @@ -80,8 +81,8 @@ object GlobalSettingsStore {
customDnsServers = this[KEY_CUSTOM_DNS_SERVERS] ?: "",
fakeDnsEnabled = this[KEY_FAKE_DNS_ENABLED] ?: true,
internetSharingEnabled = this[KEY_INTERNET_SHARING_ENABLED] ?: false,
internetSharingSocksPort = this[KEY_INTERNET_SHARING_SOCKS_PORT]?.toIntOrNull() ?: 8090,
internetSharingHttpPort = this[KEY_INTERNET_SHARING_HTTP_PORT]?.toIntOrNull() ?: 8091,
internetSharingSocksPort = this[KEY_INTERNET_SHARING_SOCKS_PORT] ?: 8090,
internetSharingHttpPort = this[KEY_INTERNET_SHARING_HTTP_PORT] ?: 8091,
internetSharingUser = this[KEY_INTERNET_SHARING_USER] ?: "",
internetSharingPass = this[KEY_INTERNET_SHARING_PASS] ?: ""
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.masterdns.vpn.service

import org.junit.Assert.assertEquals
import org.junit.Test

class MasterDnsVpnServiceConnectParseTest {
@Test
fun parsesIpv6LiteralWithPort() {
val (host, port) = MasterDnsVpnService.parseConnectTarget("[::1]:443")
assertEquals("::1", host)
assertEquals(443, port)
}

@Test
fun parsesIpv6LiteralWithoutPort() {
val (host, port) = MasterDnsVpnService.parseConnectTarget("[::1]")
assertEquals("::1", host)
assertEquals(80, port)
}

@Test
fun parsesIpv4WithPort() {
val (host, port) = MasterDnsVpnService.parseConnectTarget("127.0.0.1:8080")
assertEquals("127.0.0.1", host)
assertEquals(8080, port)
}

@Test
fun parsesDomainWithoutPort() {
val (host, port) = MasterDnsVpnService.parseConnectTarget("example.com")
assertEquals("example.com", host)
assertEquals(80, port)
}

@Test
fun coercesOutOfRangePortToClampedValue() {
val (host, port) = MasterDnsVpnService.parseConnectTarget("example.com:99999")
assertEquals("example.com", host)
assertEquals(65535, port)
}
}
Loading