Files
amnezia-client/client/android/protocolApi/src/main/kotlin/Protocol.kt
T

164 lines
5.8 KiB
Kotlin
Raw Normal View History

2023-11-23 15:45:55 +03:00
package org.amnezia.vpn.protocol
import android.content.Context
import android.net.IpPrefix
import android.net.VpnService
import android.net.VpnService.Builder
import android.os.Build
import android.system.OsConstants
import androidx.annotation.RequiresApi
import kotlinx.coroutines.flow.MutableStateFlow
import org.amnezia.vpn.util.Log
2023-12-01 00:12:50 +03:00
import org.amnezia.vpn.util.net.InetNetwork
2023-11-23 15:45:55 +03:00
import org.json.JSONObject
private const val TAG = "Protocol"
const val VPN_SESSION_NAME = "AmneziaVPN"
2023-12-01 00:12:50 +03:00
private const val SPLIT_TUNNEL_DISABLE = 0
private const val SPLIT_TUNNEL_INCLUDE = 1
private const val SPLIT_TUNNEL_EXCLUDE = 2
2023-11-26 13:07:31 +03:00
abstract class Protocol {
2023-11-23 15:45:55 +03:00
abstract val statistics: Statistics
2024-06-18 20:46:21 +03:00
protected lateinit var context: Context
protected lateinit var state: MutableStateFlow<ProtocolState>
protected lateinit var onError: (String) -> Unit
2024-06-18 20:46:21 +03:00
protected var isInitialized: Boolean = false
2023-11-23 15:45:55 +03:00
2024-06-18 20:46:21 +03:00
fun initialize(context: Context, state: MutableStateFlow<ProtocolState>, onError: (String) -> Unit) {
this.context = context
this.state = state
this.onError = onError
2024-06-18 20:46:21 +03:00
internalInit()
isInitialized = true
}
2023-11-26 13:07:31 +03:00
2024-06-18 20:46:21 +03:00
protected abstract fun internalInit()
abstract suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
2023-11-23 15:45:55 +03:00
2023-11-26 13:07:31 +03:00
abstract fun stopVpn()
2023-11-23 15:45:55 +03:00
abstract fun reconnectVpn(vpnBuilder: Builder)
protected fun ProtocolConfig.Builder.configSplitTunneling(config: JSONObject) {
if (!allowSplitTunneling) {
Log.i(TAG, "Global address split tunneling is prohibited, " +
"only tunneling from the protocol config is used")
return
}
2023-12-01 00:12:50 +03:00
val splitTunnelType = config.optInt("splitTunnelType")
if (splitTunnelType == SPLIT_TUNNEL_DISABLE) return
val splitTunnelSites = config.getJSONArray("splitTunnelSites")
val addressHandlerFunc = when (splitTunnelType) {
SPLIT_TUNNEL_INCLUDE -> ::includeAddress
SPLIT_TUNNEL_EXCLUDE -> ::excludeAddress
2023-12-01 00:12:50 +03:00
else -> throw BadConfigException("Unexpected value of the 'splitTunnelType' parameter: $splitTunnelType")
}
for (i in 0 until splitTunnelSites.length()) {
val address = InetNetwork.parse(splitTunnelSites.getString(i))
addressHandlerFunc(address)
2023-12-01 00:12:50 +03:00
}
}
2024-04-01 18:45:00 +07:00
protected fun ProtocolConfig.Builder.configAppSplitTunneling(config: JSONObject) {
val splitTunnelType = config.optInt("appSplitTunnelType")
if (splitTunnelType == SPLIT_TUNNEL_DISABLE) return
val splitTunnelApps = config.getJSONArray("splitTunnelApps")
val appHandlerFunc = when (splitTunnelType) {
SPLIT_TUNNEL_INCLUDE -> ::includeApplication
SPLIT_TUNNEL_EXCLUDE -> ::excludeApplication
else -> throw BadConfigException("Unexpected value of the 'appSplitTunnelType' parameter: $splitTunnelType")
}
for (i in 0 until splitTunnelApps.length()) {
appHandlerFunc(splitTunnelApps.getString(i))
}
}
2023-11-26 13:07:31 +03:00
protected open fun buildVpnInterface(config: ProtocolConfig, vpnBuilder: Builder) {
2023-11-23 15:45:55 +03:00
vpnBuilder.setSession(VPN_SESSION_NAME)
for (addr in config.addresses) {
Log.d(TAG, "addAddress: $addr")
vpnBuilder.addAddress(addr)
}
for (addr in config.dnsServers) {
Log.d(TAG, "addDnsServer: $addr")
vpnBuilder.addDnsServer(addr)
}
// fix for Samsung android ignoring DNS servers outside the VPN route range
if (Build.BRAND == "samsung") {
for (addr in config.dnsServers) {
Log.d(TAG, "addRoute: $addr")
vpnBuilder.addRoute(InetNetwork(addr))
}
}
config.searchDomain?.let {
Log.d(TAG, "addSearchDomain: $it")
vpnBuilder.addSearchDomain(it)
}
2024-05-12 18:04:14 +03:00
for ((inetNetwork, include) in config.routes) {
if (include) {
Log.d(TAG, "addRoute: $inetNetwork")
vpnBuilder.addRoute(inetNetwork)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Log.d(TAG, "excludeRoute: $inetNetwork")
vpnBuilder.excludeRoute(inetNetwork)
} else {
Log.e(TAG, "Trying to exclude route $inetNetwork on old Android")
}
}
}
2023-11-23 15:45:55 +03:00
2024-04-01 18:45:00 +07:00
for (app in config.includedApplications) {
Log.d(TAG, "addAllowedApplication")
2024-04-01 18:45:00 +07:00
vpnBuilder.addAllowedApplication(app)
}
for (app in config.excludedApplications) {
Log.d(TAG, "addDisallowedApplication")
vpnBuilder.addDisallowedApplication(app)
}
2023-11-23 15:45:55 +03:00
Log.d(TAG, "setMtu: ${config.mtu}")
2023-11-23 15:45:55 +03:00
vpnBuilder.setMtu(config.mtu)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
config.httpProxy?.let {
Log.d(TAG, "setHttpProxy: $it")
vpnBuilder.setHttpProxy(it)
}
}
if (config.allowAllAF) {
Log.d(TAG, "allowFamily")
vpnBuilder.allowFamily(OsConstants.AF_INET)
vpnBuilder.allowFamily(OsConstants.AF_INET6)
}
Log.d(TAG, "setBlocking: ${config.blockingMode}")
2023-11-23 15:45:55 +03:00
vpnBuilder.setBlocking(config.blockingMode)
vpnBuilder.setUnderlyingNetworks(null)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
vpnBuilder.setMetered(false)
}
}
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
private fun VpnService.Builder.addRoute(addr: InetNetwork) = addRoute(addr.address, addr.mask)
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun VpnService.Builder.excludeRoute(addr: InetNetwork) = excludeRoute(IpPrefix(addr.address, addr.mask))