feat: implement reconnection in AWG by turning the VPN off and on (#2046)

This commit is contained in:
albexk
2025-12-11 13:51:19 +03:00
committed by GitHub
parent 3e6f0c0342
commit 5103bc640e
5 changed files with 29 additions and 13 deletions

View File

@@ -93,7 +93,7 @@ open class OpenVpn : Protocol() {
openVpnClient = null openVpnClient = null
} }
override fun reconnectVpn(vpnBuilder: Builder) { override fun reconnectVpn(vpnBuilder: Builder, protect: (Int) -> Boolean) {
openVpnClient?.let { openVpnClient?.let {
it.establish = makeEstablish(vpnBuilder) it.establish = makeEstablish(vpnBuilder)
it.reconnect(0) it.reconnect(0)

View File

@@ -42,7 +42,7 @@ abstract class Protocol {
abstract fun stopVpn() abstract fun stopVpn()
abstract fun reconnectVpn(vpnBuilder: Builder) abstract fun reconnectVpn(vpnBuilder: Builder, protect: (Int) -> Boolean)
protected fun ProtocolConfig.Builder.configSplitTunneling(config: JSONObject) { protected fun ProtocolConfig.Builder.configSplitTunneling(config: JSONObject) {
if (!allowSplitTunneling) { if (!allowSplitTunneling) {

View File

@@ -565,7 +565,7 @@ open class AmneziaVpnService : VpnService() {
protocolState.value = RECONNECTING protocolState.value = RECONNECTING
connectionJob = connectionScope.launch { connectionJob = connectionScope.launch {
vpnProto?.protocol?.reconnectVpn(Builder()) vpnProto?.protocol?.reconnectVpn(Builder(), ::protect)
} }
} }

View File

@@ -12,6 +12,7 @@ import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
import org.amnezia.vpn.protocol.Statistics import org.amnezia.vpn.protocol.Statistics
import org.amnezia.vpn.protocol.VpnException
import org.amnezia.vpn.protocol.VpnStartException import org.amnezia.vpn.protocol.VpnStartException
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.Log
@@ -27,6 +28,7 @@ private const val TAG = "Wireguard"
open class Wireguard : Protocol() { open class Wireguard : Protocol() {
private var tunnelHandle: Int = -1 private var tunnelHandle: Int = -1
private var config: WireguardConfig? = null // save config for reconnect
protected open val ifName: String = "amn0" protected open val ifName: String = "amn0"
private lateinit var scope: CoroutineScope private lateinit var scope: CoroutineScope
private var statusJob: Job? = null private var statusJob: Job? = null
@@ -61,6 +63,7 @@ open class Wireguard : Protocol() {
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) { override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val wireguardConfig = parseConfig(config) val wireguardConfig = parseConfig(config)
start(wireguardConfig, vpnBuilder, protect) start(wireguardConfig, vpnBuilder, protect)
this.config = wireguardConfig
} }
protected open fun parseConfig(config: JSONObject): WireguardConfig { protected open fun parseConfig(config: JSONObject): WireguardConfig {
@@ -133,8 +136,13 @@ open class Wireguard : Protocol() {
configData.optStringOrNull("I5")?.let { setI5(it) } configData.optStringOrNull("I5")?.let { setI5(it) }
} }
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) { private fun start(
if (tunnelHandle != -1) { config: WireguardConfig,
vpnBuilder: Builder,
protect: (Int) -> Boolean,
stopExistingVpn: Boolean = false
) {
if (!stopExistingVpn && tunnelHandle != -1) {
Log.w(TAG, "Tunnel already up") Log.w(TAG, "Tunnel already up")
return return
} }
@@ -142,6 +150,9 @@ open class Wireguard : Protocol() {
buildVpnInterface(config, vpnBuilder) buildVpnInterface(config, vpnBuilder)
vpnBuilder.establish().use { tunFd -> vpnBuilder.establish().use { tunFd ->
if (stopExistingVpn && tunnelHandle != -1) {
turnOffVpn()
}
if (tunFd == null) { if (tunFd == null) {
throw VpnStartException("Create VPN interface: permission not granted or revoked") throw VpnStartException("Create VPN interface: permission not granted or revoked")
} }
@@ -198,20 +209,25 @@ open class Wireguard : Protocol() {
return lastHandshake return lastHandshake
} }
override fun stopVpn() { private fun turnOffVpn() {
if (tunnelHandle == -1) {
Log.w(TAG, "Tunnel already down")
return
}
statusJob?.cancel() statusJob?.cancel()
statusJob = null statusJob = null
val handleToClose = tunnelHandle val handleToClose = tunnelHandle
tunnelHandle = -1 tunnelHandle = -1
GoBackend.awgTurnOff(handleToClose) GoBackend.awgTurnOff(handleToClose)
}
override fun stopVpn() {
if (tunnelHandle == -1) {
Log.w(TAG, "Tunnel already down")
return
}
turnOffVpn()
state.value = DISCONNECTED state.value = DISCONNECTED
} }
override fun reconnectVpn(vpnBuilder: Builder) { override fun reconnectVpn(vpnBuilder: Builder, protect: (Int) -> Boolean) {
state.value = CONNECTED val config = this.config ?: throw VpnException("Reconnect config is empty")
start(config, vpnBuilder, protect, true)
} }
} }

View File

@@ -157,7 +157,7 @@ class Xray : Protocol() {
state.value = DISCONNECTED state.value = DISCONNECTED
} }
override fun reconnectVpn(vpnBuilder: Builder) { override fun reconnectVpn(vpnBuilder: Builder, protect: (Int) -> Boolean) {
state.value = CONNECTED state.value = CONNECTED
} }