Merge branch 'dev' into feature/android-gpb
# Conflicts: # CMakeLists.txt
This commit is contained in:
commit
3bd6f704e9
36 changed files with 482 additions and 321 deletions
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
|
|
@ -181,7 +181,7 @@ jobs:
|
||||||
- name: 'Install go'
|
- name: 'Install go'
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22.1'
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: 'Setup gomobile'
|
- name: 'Setup gomobile'
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
|
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
|
||||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
|
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
|
||||||
|
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,21 @@
|
||||||
package org.amnezia.vpn.protocol.awg
|
package org.amnezia.vpn.protocol.awg
|
||||||
|
|
||||||
import org.amnezia.vpn.protocol.wireguard.Wireguard
|
import org.amnezia.vpn.protocol.wireguard.Wireguard
|
||||||
import org.amnezia.vpn.util.optStringOrNull
|
import org.amnezia.vpn.protocol.wireguard.WireguardConfig
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
class Awg : Wireguard() {
|
class Awg : Wireguard() {
|
||||||
|
|
||||||
override val ifName: String = "awg0"
|
override val ifName: String = "awg0"
|
||||||
|
|
||||||
override fun parseConfig(config: JSONObject): AwgConfig {
|
override fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configData = config.getJSONObject("awg_config_data")
|
val configData = config.getJSONObject("awg_config_data")
|
||||||
return AwgConfig.build {
|
return WireguardConfig.build {
|
||||||
|
setUseProtocolExtension(true)
|
||||||
|
configExtensionParameters(configData)
|
||||||
configWireguard(config, configData)
|
configWireguard(config, configData)
|
||||||
configSplitTunneling(config)
|
configSplitTunneling(config)
|
||||||
configAppSplitTunneling(config)
|
configAppSplitTunneling(config)
|
||||||
configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
|
|
||||||
configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
|
|
||||||
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
|
||||||
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
|
||||||
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
|
||||||
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
|
||||||
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
|
||||||
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
|
||||||
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
package org.amnezia.vpn.protocol.awg
|
|
||||||
|
|
||||||
import org.amnezia.vpn.protocol.BadConfigException
|
|
||||||
import org.amnezia.vpn.protocol.wireguard.WireguardConfig
|
|
||||||
|
|
||||||
class AwgConfig private constructor(
|
|
||||||
wireguardConfigBuilder: WireguardConfig.Builder,
|
|
||||||
val jc: Int,
|
|
||||||
val jmin: Int,
|
|
||||||
val jmax: Int,
|
|
||||||
val s1: Int,
|
|
||||||
val s2: Int,
|
|
||||||
val h1: Long,
|
|
||||||
val h2: Long,
|
|
||||||
val h3: Long,
|
|
||||||
val h4: Long
|
|
||||||
) : WireguardConfig(wireguardConfigBuilder) {
|
|
||||||
|
|
||||||
private constructor(builder: Builder) : this(
|
|
||||||
builder,
|
|
||||||
builder.jc,
|
|
||||||
builder.jmin,
|
|
||||||
builder.jmax,
|
|
||||||
builder.s1,
|
|
||||||
builder.s2,
|
|
||||||
builder.h1,
|
|
||||||
builder.h2,
|
|
||||||
builder.h3,
|
|
||||||
builder.h4
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
|
||||||
super.appendDeviceLine(this)
|
|
||||||
appendLine("jc=$jc")
|
|
||||||
appendLine("jmin=$jmin")
|
|
||||||
appendLine("jmax=$jmax")
|
|
||||||
appendLine("s1=$s1")
|
|
||||||
appendLine("s2=$s2")
|
|
||||||
appendLine("h1=$h1")
|
|
||||||
appendLine("h2=$h2")
|
|
||||||
appendLine("h3=$h3")
|
|
||||||
appendLine("h4=$h4")
|
|
||||||
}
|
|
||||||
|
|
||||||
class Builder : WireguardConfig.Builder() {
|
|
||||||
|
|
||||||
private var _jc: Int? = null
|
|
||||||
internal var jc: Int
|
|
||||||
get() = _jc ?: throw BadConfigException("AWG: parameter jc is undefined")
|
|
||||||
private set(value) { _jc = value }
|
|
||||||
|
|
||||||
private var _jmin: Int? = null
|
|
||||||
internal var jmin: Int
|
|
||||||
get() = _jmin ?: throw BadConfigException("AWG: parameter jmin is undefined")
|
|
||||||
private set(value) { _jmin = value }
|
|
||||||
|
|
||||||
private var _jmax: Int? = null
|
|
||||||
internal var jmax: Int
|
|
||||||
get() = _jmax ?: throw BadConfigException("AWG: parameter jmax is undefined")
|
|
||||||
private set(value) { _jmax = value }
|
|
||||||
|
|
||||||
private var _s1: Int? = null
|
|
||||||
internal var s1: Int
|
|
||||||
get() = _s1 ?: throw BadConfigException("AWG: parameter s1 is undefined")
|
|
||||||
private set(value) { _s1 = value }
|
|
||||||
|
|
||||||
private var _s2: Int? = null
|
|
||||||
internal var s2: Int
|
|
||||||
get() = _s2 ?: throw BadConfigException("AWG: parameter s2 is undefined")
|
|
||||||
private set(value) { _s2 = value }
|
|
||||||
|
|
||||||
private var _h1: Long? = null
|
|
||||||
internal var h1: Long
|
|
||||||
get() = _h1 ?: throw BadConfigException("AWG: parameter h1 is undefined")
|
|
||||||
private set(value) { _h1 = value }
|
|
||||||
|
|
||||||
private var _h2: Long? = null
|
|
||||||
internal var h2: Long
|
|
||||||
get() = _h2 ?: throw BadConfigException("AWG: parameter h2 is undefined")
|
|
||||||
private set(value) { _h2 = value }
|
|
||||||
|
|
||||||
private var _h3: Long? = null
|
|
||||||
internal var h3: Long
|
|
||||||
get() = _h3 ?: throw BadConfigException("AWG: parameter h3 is undefined")
|
|
||||||
private set(value) { _h3 = value }
|
|
||||||
|
|
||||||
private var _h4: Long? = null
|
|
||||||
internal var h4: Long
|
|
||||||
get() = _h4 ?: throw BadConfigException("AWG: parameter h4 is undefined")
|
|
||||||
private set(value) { _h4 = value }
|
|
||||||
|
|
||||||
fun setJc(jc: Int) = apply { this.jc = jc }
|
|
||||||
fun setJmin(jmin: Int) = apply { this.jmin = jmin }
|
|
||||||
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
|
||||||
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
|
||||||
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
|
||||||
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
|
||||||
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
|
||||||
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
|
||||||
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
|
||||||
|
|
||||||
override fun build(): AwgConfig = configBuild().run { AwgConfig(this@Builder) }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
inline fun build(block: Builder.() -> Unit): AwgConfig = Builder().apply(block).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,10 +3,16 @@ package org.amnezia.vpn.protocol.cloak
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import net.openvpn.ovpn3.ClientAPI_Config
|
import net.openvpn.ovpn3.ClientAPI_Config
|
||||||
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
class Cloak : OpenVpn() {
|
class Cloak : OpenVpn() {
|
||||||
|
|
||||||
|
override fun internalInit() {
|
||||||
|
super.internalInit()
|
||||||
|
if (!isInitialized) loadSharedLibrary(context, "ck-ovpn-plugin")
|
||||||
|
}
|
||||||
|
|
||||||
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
||||||
val openVpnConfig = ClientAPI_Config()
|
val openVpnConfig = ClientAPI_Config()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import org.amnezia.vpn.protocol.Protocol
|
||||||
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.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
import org.amnezia.vpn.util.net.getLocalNetworks
|
import org.amnezia.vpn.util.net.getLocalNetworks
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
|
|
@ -34,7 +35,10 @@ open class OpenVpn : Protocol() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun internalInit() {
|
override fun internalInit() {
|
||||||
if (!isInitialized) loadSharedLibrary(context, "ovpn3")
|
if (!isInitialized) {
|
||||||
|
loadSharedLibrary(context, "ovpn3")
|
||||||
|
loadSharedLibrary(context, "ovpnutil")
|
||||||
|
}
|
||||||
if (this::scope.isInitialized) {
|
if (this::scope.isInitialized) {
|
||||||
scope.cancel()
|
scope.cancel()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package org.amnezia.vpn.protocol
|
||||||
|
|
||||||
sealed class ProtocolException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
sealed class ProtocolException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
||||||
class LoadLibraryException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
|
||||||
class BadConfigException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
class BadConfigException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
||||||
|
|
||||||
class VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
class VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
||||||
|
|
|
||||||
|
|
@ -158,60 +158,6 @@ abstract class Protocol {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
vpnBuilder.setMetered(false)
|
vpnBuilder.setMetered(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean {
|
|
||||||
Log.d(TAG, "Extracting library: $libraryName")
|
|
||||||
val apks = hashSetOf<String>()
|
|
||||||
context.applicationInfo.run {
|
|
||||||
sourceDir?.let { apks += it }
|
|
||||||
splitSourceDirs?.let { apks += it }
|
|
||||||
}
|
|
||||||
for (abi in Build.SUPPORTED_ABIS) {
|
|
||||||
for (apk in apks) {
|
|
||||||
ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
|
|
||||||
val mappedName = System.mapLibraryName(libraryName)
|
|
||||||
val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
|
|
||||||
val zipEntry = zipFile.getEntry(libraryZipPath)
|
|
||||||
zipEntry?.let {
|
|
||||||
Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
|
|
||||||
FileOutputStream(destination).use { outStream ->
|
|
||||||
zipFile.getInputStream(zipEntry).use { inStream ->
|
|
||||||
inStream.copyTo(outStream, 32 * 1024)
|
|
||||||
outStream.fd.sync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
|
||||||
fun loadSharedLibrary(context: Context, libraryName: String) {
|
|
||||||
Log.d(TAG, "Loading library: $libraryName")
|
|
||||||
try {
|
|
||||||
System.loadLibrary(libraryName)
|
|
||||||
return
|
|
||||||
} catch (_: UnsatisfiedLinkError) {
|
|
||||||
Log.d(TAG, "Failed to load library, try to extract it from apk")
|
|
||||||
}
|
|
||||||
var tempFile: File? = null
|
|
||||||
try {
|
|
||||||
tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
|
|
||||||
if (extractLibrary(context, libraryName, tempFile)) {
|
|
||||||
System.load(tempFile.absolutePath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw LoadLibraryException("Failed to load library apk: $libraryName", e)
|
|
||||||
} finally {
|
|
||||||
tempFile?.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
|
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
|
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
|
||||||
|
|
||||||
<array name="bundled_libs">
|
<array name="bundled_libs">
|
||||||
<!-- %%INSERT_EXTRA_LIBS%% -->
|
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<array name="qt_libs">
|
<array name="qt_libs">
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import kotlinx.coroutines.withContext
|
||||||
import org.amnezia.vpn.protocol.getStatistics
|
import org.amnezia.vpn.protocol.getStatistics
|
||||||
import org.amnezia.vpn.protocol.getStatus
|
import org.amnezia.vpn.protocol.getStatus
|
||||||
import org.amnezia.vpn.qt.QtAndroidController
|
import org.amnezia.vpn.qt.QtAndroidController
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.Prefs
|
import org.amnezia.vpn.util.Prefs
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
|
|
@ -159,6 +160,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
Log.d(TAG, "Billing provider: ${BillingProvider().type()}")
|
Log.d(TAG, "Billing provider: ${BillingProvider().type()}")
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d(TAG, "Create Amnezia activity: $intent")
|
Log.d(TAG, "Create Amnezia activity: $intent")
|
||||||
|
loadLibs()
|
||||||
window.apply {
|
window.apply {
|
||||||
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
statusBarColor = getColor(R.color.black)
|
statusBarColor = getColor(R.color.black)
|
||||||
|
|
@ -180,6 +182,17 @@ class AmneziaActivity : QtActivity() {
|
||||||
runBlocking { vpnProto = proto.await() }
|
runBlocking { vpnProto = proto.await() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadLibs() {
|
||||||
|
listOf(
|
||||||
|
"rsapss",
|
||||||
|
"crypto_3",
|
||||||
|
"ssl_3",
|
||||||
|
"ssh"
|
||||||
|
).forEach {
|
||||||
|
loadSharedLibrary(this.applicationContext, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun registerBroadcastReceivers() {
|
private fun registerBroadcastReceivers() {
|
||||||
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
registerBroadcastReceiver(
|
registerBroadcastReceiver(
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.amnezia.vpn.protocol.BadConfigException
|
import org.amnezia.vpn.protocol.BadConfigException
|
||||||
import org.amnezia.vpn.protocol.LoadLibraryException
|
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTING
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTING
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
||||||
|
|
@ -50,6 +49,7 @@ import org.amnezia.vpn.protocol.ProtocolState.UNKNOWN
|
||||||
import org.amnezia.vpn.protocol.VpnException
|
import org.amnezia.vpn.protocol.VpnException
|
||||||
import org.amnezia.vpn.protocol.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
import org.amnezia.vpn.protocol.putStatus
|
import org.amnezia.vpn.protocol.putStatus
|
||||||
|
import org.amnezia.vpn.util.LoadLibraryException
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.Prefs
|
import org.amnezia.vpn.util.Prefs
|
||||||
import org.amnezia.vpn.util.net.NetworkState
|
import org.amnezia.vpn.util.net.NetworkState
|
||||||
|
|
|
||||||
66
client/android/utils/src/main/kotlin/LibraryLoader.kt
Normal file
66
client/android/utils/src/main/kotlin/LibraryLoader.kt
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.amnezia.vpn.util
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
|
private const val TAG = "LibraryLoader"
|
||||||
|
|
||||||
|
object LibraryLoader {
|
||||||
|
private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean {
|
||||||
|
Log.d(TAG, "Extracting library: $libraryName")
|
||||||
|
val apks = hashSetOf<String>()
|
||||||
|
context.applicationInfo.run {
|
||||||
|
sourceDir?.let { apks += it }
|
||||||
|
splitSourceDirs?.let { apks += it }
|
||||||
|
}
|
||||||
|
for (abi in Build.SUPPORTED_ABIS) {
|
||||||
|
for (apk in apks) {
|
||||||
|
ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
|
||||||
|
val mappedName = System.mapLibraryName(libraryName)
|
||||||
|
val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
|
||||||
|
val zipEntry = zipFile.getEntry(libraryZipPath)
|
||||||
|
zipEntry?.let {
|
||||||
|
Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
|
||||||
|
FileOutputStream(destination).use { outStream ->
|
||||||
|
zipFile.getInputStream(zipEntry).use { inStream ->
|
||||||
|
inStream.copyTo(outStream, 32 * 1024)
|
||||||
|
outStream.fd.sync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
|
fun loadSharedLibrary(context: Context, libraryName: String) {
|
||||||
|
Log.d(TAG, "Loading library: $libraryName")
|
||||||
|
try {
|
||||||
|
System.loadLibrary(libraryName)
|
||||||
|
return
|
||||||
|
} catch (_: UnsatisfiedLinkError) {
|
||||||
|
Log.d(TAG, "Failed to load library, try to extract it from apk")
|
||||||
|
}
|
||||||
|
var tempFile: File? = null
|
||||||
|
try {
|
||||||
|
tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
|
||||||
|
if (extractLibrary(context, libraryName, tempFile)) {
|
||||||
|
System.load(tempFile.absolutePath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw LoadLibraryException("Failed to load library apk: $libraryName", e)
|
||||||
|
} finally {
|
||||||
|
tempFile?.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoadLibraryException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
@ -60,7 +60,7 @@ private val parseNumericAddressCompat: (String) -> InetAddress =
|
||||||
internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6
|
internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6
|
||||||
.replace("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)".toRegex(), "::$2")
|
.replace("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)".toRegex(), "::$2")
|
||||||
|
|
||||||
internal val InetAddress.ip: String
|
val InetAddress.ip: String
|
||||||
get() = if (this is Inet4Address) {
|
get() = if (this is Inet4Address) {
|
||||||
hostAddress!!
|
hostAddress!!
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package org.amnezia.vpn.protocol.wireguard
|
||||||
import android.net.VpnService.Builder
|
import android.net.VpnService.Builder
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TreeMap
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -13,6 +12,7 @@ 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.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.asSequence
|
import org.amnezia.vpn.util.asSequence
|
||||||
import org.amnezia.vpn.util.net.InetEndpoint
|
import org.amnezia.vpn.util.net.InetEndpoint
|
||||||
|
|
@ -129,12 +129,29 @@ open class Wireguard : Protocol() {
|
||||||
val port = configData.getInt("port")
|
val port = configData.getInt("port")
|
||||||
setEndpoint(InetEndpoint(host, port))
|
setEndpoint(InetEndpoint(host, port))
|
||||||
|
|
||||||
|
if (configData.optBoolean("isObfuscationEnabled")) {
|
||||||
|
setUseProtocolExtension(true)
|
||||||
|
configExtensionParameters(configData)
|
||||||
|
}
|
||||||
|
|
||||||
configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
|
configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
|
||||||
configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
|
configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
|
||||||
configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
|
configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
|
||||||
configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun WireguardConfig.Builder.configExtensionParameters(configData: JSONObject) {
|
||||||
|
configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
|
||||||
|
configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
|
||||||
|
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
||||||
|
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
||||||
|
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
||||||
|
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
||||||
|
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
||||||
|
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
||||||
|
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
if (tunnelHandle != -1) {
|
if (tunnelHandle != -1) {
|
||||||
Log.w(TAG, "Tunnel already up")
|
Log.w(TAG, "Tunnel already up")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import org.amnezia.vpn.protocol.BadConfigException
|
||||||
import org.amnezia.vpn.protocol.ProtocolConfig
|
import org.amnezia.vpn.protocol.ProtocolConfig
|
||||||
import org.amnezia.vpn.util.net.InetEndpoint
|
import org.amnezia.vpn.util.net.InetEndpoint
|
||||||
|
|
||||||
|
|
@ -12,7 +13,17 @@ open class WireguardConfig protected constructor(
|
||||||
val persistentKeepalive: Int,
|
val persistentKeepalive: Int,
|
||||||
val publicKeyHex: String,
|
val publicKeyHex: String,
|
||||||
val preSharedKeyHex: String?,
|
val preSharedKeyHex: String?,
|
||||||
val privateKeyHex: String
|
val privateKeyHex: String,
|
||||||
|
val useProtocolExtension: Boolean,
|
||||||
|
val jc: Int?,
|
||||||
|
val jmin: Int?,
|
||||||
|
val jmax: Int?,
|
||||||
|
val s1: Int?,
|
||||||
|
val s2: Int?,
|
||||||
|
val h1: Long?,
|
||||||
|
val h2: Long?,
|
||||||
|
val h3: Long?,
|
||||||
|
val h4: Long?
|
||||||
) : ProtocolConfig(protocolConfigBuilder) {
|
) : ProtocolConfig(protocolConfigBuilder) {
|
||||||
|
|
||||||
protected constructor(builder: Builder) : this(
|
protected constructor(builder: Builder) : this(
|
||||||
|
|
@ -21,7 +32,17 @@ open class WireguardConfig protected constructor(
|
||||||
builder.persistentKeepalive,
|
builder.persistentKeepalive,
|
||||||
builder.publicKeyHex,
|
builder.publicKeyHex,
|
||||||
builder.preSharedKeyHex,
|
builder.preSharedKeyHex,
|
||||||
builder.privateKeyHex
|
builder.privateKeyHex,
|
||||||
|
builder.useProtocolExtension,
|
||||||
|
builder.jc,
|
||||||
|
builder.jmin,
|
||||||
|
builder.jmax,
|
||||||
|
builder.s1,
|
||||||
|
builder.s2,
|
||||||
|
builder.h1,
|
||||||
|
builder.h2,
|
||||||
|
builder.h3,
|
||||||
|
builder.h4
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
||||||
|
|
@ -33,6 +54,30 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
||||||
appendLine("private_key=$privateKeyHex")
|
appendLine("private_key=$privateKeyHex")
|
||||||
|
if (useProtocolExtension) {
|
||||||
|
validateProtocolExtensionParameters()
|
||||||
|
appendLine("jc=$jc")
|
||||||
|
appendLine("jmin=$jmin")
|
||||||
|
appendLine("jmax=$jmax")
|
||||||
|
appendLine("s1=$s1")
|
||||||
|
appendLine("s2=$s2")
|
||||||
|
appendLine("h1=$h1")
|
||||||
|
appendLine("h2=$h2")
|
||||||
|
appendLine("h3=$h3")
|
||||||
|
appendLine("h4=$h4")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateProtocolExtensionParameters() {
|
||||||
|
if (jc == null) throw BadConfigException("Parameter jc is undefined")
|
||||||
|
if (jmin == null) throw BadConfigException("Parameter jmin is undefined")
|
||||||
|
if (jmax == null) throw BadConfigException("Parameter jmax is undefined")
|
||||||
|
if (s1 == null) throw BadConfigException("Parameter s1 is undefined")
|
||||||
|
if (s2 == null) throw BadConfigException("Parameter s2 is undefined")
|
||||||
|
if (h1 == null) throw BadConfigException("Parameter h1 is undefined")
|
||||||
|
if (h2 == null) throw BadConfigException("Parameter h2 is undefined")
|
||||||
|
if (h3 == null) throw BadConfigException("Parameter h3 is undefined")
|
||||||
|
if (h4 == null) throw BadConfigException("Parameter h4 is undefined")
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun appendPeerLine(sb: StringBuilder) = with(sb) {
|
open fun appendPeerLine(sb: StringBuilder) = with(sb) {
|
||||||
|
|
@ -65,6 +110,18 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
override var mtu: Int = WIREGUARD_DEFAULT_MTU
|
override var mtu: Int = WIREGUARD_DEFAULT_MTU
|
||||||
|
|
||||||
|
internal var useProtocolExtension: Boolean = false
|
||||||
|
|
||||||
|
internal var jc: Int? = null
|
||||||
|
internal var jmin: Int? = null
|
||||||
|
internal var jmax: Int? = null
|
||||||
|
internal var s1: Int? = null
|
||||||
|
internal var s2: Int? = null
|
||||||
|
internal var h1: Long? = null
|
||||||
|
internal var h2: Long? = null
|
||||||
|
internal var h3: Long? = null
|
||||||
|
internal var h4: Long? = null
|
||||||
|
|
||||||
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
||||||
|
|
||||||
fun setPersistentKeepalive(persistentKeepalive: Int) = apply { this.persistentKeepalive = persistentKeepalive }
|
fun setPersistentKeepalive(persistentKeepalive: Int) = apply { this.persistentKeepalive = persistentKeepalive }
|
||||||
|
|
@ -75,6 +132,18 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
fun setPrivateKeyHex(privateKeyHex: String) = apply { this.privateKeyHex = privateKeyHex }
|
fun setPrivateKeyHex(privateKeyHex: String) = apply { this.privateKeyHex = privateKeyHex }
|
||||||
|
|
||||||
|
fun setUseProtocolExtension(useProtocolExtension: Boolean) = apply { this.useProtocolExtension = useProtocolExtension }
|
||||||
|
|
||||||
|
fun setJc(jc: Int) = apply { this.jc = jc }
|
||||||
|
fun setJmin(jmin: Int) = apply { this.jmin = jmin }
|
||||||
|
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
||||||
|
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
||||||
|
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
||||||
|
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
||||||
|
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
||||||
|
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
||||||
|
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
||||||
|
|
||||||
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import org.amnezia.vpn.protocol.xray.libXray.Logger
|
||||||
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
|
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
|
import org.amnezia.vpn.util.net.ip
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
|
@ -61,7 +62,15 @@ class Xray : Protocol() {
|
||||||
.put("loglevel", "warning")
|
.put("loglevel", "warning")
|
||||||
.put("access", "none") // disable access log
|
.put("access", "none") // disable access log
|
||||||
|
|
||||||
start(xrayConfig, xrayJsonConfig.toString(), vpnBuilder, protect)
|
var xrayJsonConfigString = xrayJsonConfig.toString()
|
||||||
|
config.getString("hostName").let { hostName ->
|
||||||
|
val ipAddress = parseInetAddress(hostName).ip
|
||||||
|
if (hostName != ipAddress) {
|
||||||
|
xrayJsonConfigString = xrayJsonConfigString.replace(hostName, ipAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start(xrayConfig, xrayJsonConfigString, vpnBuilder, protect)
|
||||||
state.value = CONNECTED
|
state.value = CONNECTED
|
||||||
isRunning = true
|
isRunning = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
|
||||||
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
||||||
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
|
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
|
||||||
|
|
||||||
jConfig[config_key::persistent_keep_alive] = 25;
|
jConfig[config_key::persistent_keep_alive] = "25";
|
||||||
QJsonArray allowedIps { "0.0.0.0/0", "::/0" };
|
QJsonArray allowedIps { "0.0.0.0/0", "::/0" };
|
||||||
jConfig[config_key::allowed_ips] = allowedIps;
|
jConfig[config_key::allowed_ips] = allowedIps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,12 @@ QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
|
||||||
return Instance()->m_ipcClient;
|
return Instance()->m_ipcClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
|
||||||
|
{
|
||||||
|
if (!Instance()) return nullptr;
|
||||||
|
return Instance()->m_Tun2SocksClient;
|
||||||
|
}
|
||||||
|
|
||||||
bool IpcClient::init(IpcClient *instance)
|
bool IpcClient::init(IpcClient *instance)
|
||||||
{
|
{
|
||||||
m_instance = instance;
|
m_instance = instance;
|
||||||
|
|
@ -44,6 +50,12 @@ bool IpcClient::init(IpcClient *instance)
|
||||||
qWarning() << "IpcClient replica is not connected!";
|
qWarning() << "IpcClient replica is not connected!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instance()->m_Tun2SocksClient.reset(Instance()->m_ClientNode.acquire<IpcProcessTun2SocksReplica>());
|
||||||
|
Instance()->m_Tun2SocksClient->waitForSource(1000);
|
||||||
|
|
||||||
|
if (!Instance()->m_Tun2SocksClient->isReplicaValid()) {
|
||||||
|
qWarning() << "IpcClient::m_Tun2SocksClient replica is not connected!";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
|
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
|
||||||
|
|
@ -51,16 +63,16 @@ bool IpcClient::init(IpcClient *instance)
|
||||||
});
|
});
|
||||||
|
|
||||||
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
|
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
|
||||||
|
|
||||||
Instance()->m_localSocket->waitForConnected();
|
Instance()->m_localSocket->waitForConnected();
|
||||||
|
|
||||||
if (!Instance()->m_ipcClient) {
|
if (!Instance()->m_ipcClient) {
|
||||||
qDebug() << "IpcClient::init failed";
|
qDebug() << "IpcClient::init failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "IpcClient::init succeed";
|
qDebug() << "IpcClient::init succeed";
|
||||||
|
|
||||||
return Instance()->m_ipcClient->isReplicaValid();
|
return (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "rep_ipc_interface_replica.h"
|
#include "rep_ipc_interface_replica.h"
|
||||||
|
#include "rep_ipc_process_tun2socks_replica.h"
|
||||||
|
|
||||||
#include "privileged_process.h"
|
#include "privileged_process.h"
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ public:
|
||||||
static IpcClient *Instance();
|
static IpcClient *Instance();
|
||||||
static bool init(IpcClient *instance);
|
static bool init(IpcClient *instance);
|
||||||
static QSharedPointer<IpcInterfaceReplica> Interface();
|
static QSharedPointer<IpcInterfaceReplica> Interface();
|
||||||
|
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
|
||||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||||
|
|
||||||
bool isSocketConnected() const;
|
bool isSocketConnected() const;
|
||||||
|
|
@ -28,8 +30,11 @@ private:
|
||||||
~IpcClient() override;
|
~IpcClient() override;
|
||||||
|
|
||||||
QRemoteObjectNode m_ClientNode;
|
QRemoteObjectNode m_ClientNode;
|
||||||
|
QRemoteObjectNode m_Tun2SocksNode;
|
||||||
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
|
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
|
||||||
QPointer<QLocalSocket> m_localSocket;
|
QPointer<QLocalSocket> m_localSocket;
|
||||||
|
QPointer<QLocalSocket> m_tun2socksSocket;
|
||||||
|
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;
|
||||||
|
|
||||||
struct ProcessDescriptor {
|
struct ProcessDescriptor {
|
||||||
ProcessDescriptor () {
|
ProcessDescriptor () {
|
||||||
|
|
|
||||||
|
|
@ -499,6 +499,20 @@ bool IosController::setupWireGuard()
|
||||||
wgConfig.insert(config_key::persistent_keep_alive, "25");
|
wgConfig.insert(config_key::persistent_keep_alive, "25");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.contains(config_key::isObfuscationEnabled) && config.value(config_key::isObfuscationEnabled).toBool()) {
|
||||||
|
wgConfig.insert(config_key::initPacketMagicHeader, config[config_key::initPacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::responsePacketMagicHeader, config[config_key::responsePacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::underloadPacketMagicHeader, config[config_key::underloadPacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::transportPacketMagicHeader, config[config_key::transportPacketMagicHeader]);
|
||||||
|
|
||||||
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
|
|
||||||
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
|
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
||||||
|
}
|
||||||
|
|
||||||
QJsonDocument wgConfigDoc(wgConfig);
|
QJsonDocument wgConfigDoc(wgConfig);
|
||||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
|
||||||
|
#include "core/networkUtilities.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "openvpnprotocol.h"
|
#include "openvpnprotocol.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
@ -127,7 +128,6 @@ void OpenVpnProtocol::sendManagementCommand(const QString &command)
|
||||||
|
|
||||||
uint OpenVpnProtocol::selectMgmtPort()
|
uint OpenVpnProtocol::selectMgmtPort()
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
quint32 port = QRandomGenerator::global()->generate();
|
quint32 port = QRandomGenerator::global()->generate();
|
||||||
port = (double)(65000 - 15001) * port / UINT32_MAX + 15001;
|
port = (double)(65000 - 15001) * port / UINT32_MAX + 15001;
|
||||||
|
|
@ -137,7 +137,6 @@ uint OpenVpnProtocol::selectMgmtPort()
|
||||||
if (ok)
|
if (ok)
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_managementPort;
|
return m_managementPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,7 +342,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||||
}
|
}
|
||||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||||
m_configData.insert("vpnServer", m_configData.value(amnezia::config_key::hostName).toString());
|
m_configData.insert("vpnServer",
|
||||||
|
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
|
||||||
IpcClient::Interface()->enablePeerTraffic(m_configData);
|
IpcClient::Interface()->enablePeerTraffic(m_configData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,6 +352,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
m_configData.insert("vpnServer",
|
||||||
|
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ namespace amnezia
|
||||||
constexpr char last_config[] = "last_config";
|
constexpr char last_config[] = "last_config";
|
||||||
|
|
||||||
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
|
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
|
||||||
|
constexpr char isObfuscationEnabled[] = "isObfuscationEnabled";
|
||||||
|
|
||||||
constexpr char junkPacketCount[] = "Jc";
|
constexpr char junkPacketCount[] = "Jc";
|
||||||
constexpr char junkPacketMinSize[] = "Jmin";
|
constexpr char junkPacketMinSize[] = "Jmin";
|
||||||
|
|
|
||||||
69
client/protocols/xrayprotocol.cpp
Normal file → Executable file
69
client/protocols/xrayprotocol.cpp
Normal file → Executable file
|
|
@ -17,6 +17,7 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent):
|
||||||
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||||
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
|
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
||||||
}
|
}
|
||||||
|
|
||||||
XrayProtocol::~XrayProtocol()
|
XrayProtocol::~XrayProtocol()
|
||||||
|
|
@ -65,7 +66,7 @@ ErrorCode XrayProtocol::start()
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
qDebug().noquote() << "XrayProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
|
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
if (exitStatus != QProcess::NormalExit) {
|
if (exitStatus != QProcess::NormalExit) {
|
||||||
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
||||||
|
|
@ -91,63 +92,32 @@ ErrorCode XrayProtocol::start()
|
||||||
|
|
||||||
ErrorCode XrayProtocol::startTun2Sock()
|
ErrorCode XrayProtocol::startTun2Sock()
|
||||||
{
|
{
|
||||||
if (!QFileInfo::exists(Utils::tun2socksPath())) {
|
m_t2sProcess->start();
|
||||||
setLastError(ErrorCode::Tun2SockExecutableMissing);
|
|
||||||
return lastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_t2sProcess = IpcClient::CreatePrivilegedProcess();
|
|
||||||
|
|
||||||
if (!m_t2sProcess) {
|
|
||||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_t2sProcess->waitForSource(1000);
|
|
||||||
if (!m_t2sProcess->isInitialized()) {
|
|
||||||
qWarning() << "IpcProcess replica is not connected!";
|
|
||||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString XrayConStr = "socks5://127.0.0.1:" + QString::number(m_localPort);
|
|
||||||
|
|
||||||
m_t2sProcess->setProgram(PermittedProcess::Tun2Socks);
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
|
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
|
||||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up",
|
|
||||||
QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255").arg(amnezia::protocols::xray::defaultLocalAddr)});
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr});
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
QStringList arguments({"-device", "utun22", "-proxy", XrayConStr});
|
|
||||||
#endif
|
|
||||||
m_t2sProcess->setArguments(arguments);
|
|
||||||
|
|
||||||
qDebug() << arguments.join(" ");
|
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::stateChanged, this,
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::errorOccurred,
|
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
|
||||||
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
|
|
||||||
|
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::stateChanged,
|
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this,
|
||||||
[&](QProcess::ProcessState newState) {
|
[&](int vpnState) {
|
||||||
qDebug() << "PrivilegedProcess stateChanged" << newState;
|
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
|
||||||
if (newState == QProcess::Running)
|
if (vpnState == Vpn::ConnectionState::Connected)
|
||||||
{
|
{
|
||||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
QList<QHostAddress> dnsAddr;
|
QList<QHostAddress> dnsAddr;
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QThread::msleep(8000);
|
||||||
|
#endif
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
QThread::msleep(5000);
|
QThread::msleep(5000);
|
||||||
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
|
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
|
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
QThread::msleep(15000);
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QThread::msleep(1000);
|
QThread::msleep(1000);
|
||||||
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
|
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
|
|
@ -156,6 +126,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
m_configData.insert("vpnServer", m_remoteAddress);
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -186,21 +157,15 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
#endif
|
#endif
|
||||||
setConnectionState(Vpn::ConnectionState::Connected);
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(Q_OS_MACOS)
|
#if !defined(Q_OS_MACOS)
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::finished, this,
|
if (vpnState == Vpn::ConnectionState::Disconnected) {
|
||||||
[&]() {
|
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
IpcClient::Interface()->deleteTun("tun2");
|
IpcClient::Interface()->deleteTun("tun2");
|
||||||
IpcClient::Interface()->StartRoutingIpv6();
|
IpcClient::Interface()->StartRoutingIpv6();
|
||||||
IpcClient::Interface()->clearSavedRoutes();
|
IpcClient::Interface()->clearSavedRoutes();
|
||||||
});
|
}
|
||||||
#endif
|
#endif
|
||||||
|
});
|
||||||
m_t2sProcess->start();
|
|
||||||
|
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +179,7 @@ void XrayProtocol::stop()
|
||||||
qDebug() << "XrayProtocol::stop()";
|
qDebug() << "XrayProtocol::stop()";
|
||||||
m_xrayProcess.terminate();
|
m_xrayProcess.terminate();
|
||||||
if (m_t2sProcess) {
|
if (m_t2sProcess) {
|
||||||
m_t2sProcess->close();
|
m_t2sProcess->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,10 @@ private:
|
||||||
QString m_secondaryDNS;
|
QString m_secondaryDNS;
|
||||||
#ifndef Q_OS_IOS
|
#ifndef Q_OS_IOS
|
||||||
QProcess m_xrayProcess;
|
QProcess m_xrayProcess;
|
||||||
QSharedPointer<PrivilegedProcess> m_t2sProcess;
|
QSharedPointer<IpcProcessTun2SocksReplica> m_t2sProcess;
|
||||||
#endif
|
#endif
|
||||||
QTemporaryFile m_xrayCfgFile;
|
QTemporaryFile m_xrayCfgFile;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // XRAYPROTOCOL_H
|
#endif // XRAYPROTOCOL_H
|
||||||
|
|
|
||||||
|
|
@ -242,24 +242,26 @@ void ImportController::processNativeWireGuardConfig()
|
||||||
auto containers = m_config.value(config_key::containers).toArray();
|
auto containers = m_config.value(config_key::containers).toArray();
|
||||||
if (!containers.isEmpty()) {
|
if (!containers.isEmpty()) {
|
||||||
auto container = containers.at(0).toObject();
|
auto container = containers.at(0).toObject();
|
||||||
auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
|
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
|
||||||
auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
|
auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
|
||||||
|
|
||||||
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
|
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
|
||||||
QString junkPacketMinSize = QString::number(10);
|
QString junkPacketMinSize = QString::number(10);
|
||||||
QString junkPacketMaxSize = QString::number(50);
|
QString junkPacketMaxSize = QString::number(50);
|
||||||
protocolConfig[config_key::junkPacketCount] = junkPacketCount;
|
clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount;
|
||||||
protocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
|
clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
|
||||||
protocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
|
clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
|
||||||
protocolConfig[config_key::initPacketJunkSize] = "0";
|
clientProtocolConfig[config_key::initPacketJunkSize] = "0";
|
||||||
protocolConfig[config_key::responsePacketJunkSize] = "0";
|
clientProtocolConfig[config_key::responsePacketJunkSize] = "0";
|
||||||
protocolConfig[config_key::initPacketMagicHeader] = "1";
|
clientProtocolConfig[config_key::initPacketMagicHeader] = "1";
|
||||||
protocolConfig[config_key::responsePacketMagicHeader] = "2";
|
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
|
||||||
protocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
||||||
protocolConfig[config_key::transportPacketMagicHeader] = "4";
|
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
||||||
|
|
||||||
containerConfig[config_key::last_config] = QString(QJsonDocument(protocolConfig).toJson());
|
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
||||||
container["wireguard"] = containerConfig;
|
|
||||||
|
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
||||||
|
container["wireguard"] = serverProtocolConfig;
|
||||||
containers.replace(0, container);
|
containers.replace(0, container);
|
||||||
m_config[config_key::containers] = containers;
|
m_config[config_key::containers] = containers;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@ Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
PageStart {
|
PageStart {
|
||||||
anchors.fill: parent
|
width: root.width
|
||||||
|
height: root.height
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
class IpcInterface
|
class IpcInterface
|
||||||
{
|
{
|
||||||
SLOT( int createPrivilegedProcess() ); // return local pid
|
SLOT( int createPrivilegedProcess() ); // return local pid
|
||||||
//SIGNAL(sendMessage(const QByteArray &message));
|
|
||||||
|
|
||||||
// Route functions
|
// Route functions
|
||||||
SLOT( int routeAddList(const QString &gw, const QStringList &ips) );
|
SLOT( int routeAddList(const QString &gw, const QStringList &ips) );
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
class IpcProcessInterface
|
class IpcProcessInterface
|
||||||
{
|
{
|
||||||
//SLOT( start(const QString &program, const QStringList &args) );
|
|
||||||
SLOT( start() );
|
SLOT( start() );
|
||||||
SLOT( close() );
|
SLOT( close() );
|
||||||
|
|
||||||
|
|
|
||||||
11
ipc/ipc_process_tun2socks.rep
Normal file
11
ipc/ipc_process_tun2socks.rep
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class IpcProcessTun2Socks
|
||||||
|
{
|
||||||
|
SLOT( start() );
|
||||||
|
SLOT( stop() );
|
||||||
|
|
||||||
|
SIGNAL( setConnectionState(int state) );
|
||||||
|
SIGNAL( stateChanged(QProcess::ProcessState newState) );
|
||||||
|
};
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
|
|
||||||
|
#include "../core/networkUtilities.h"
|
||||||
#include "../client/protocols/protocols_defs.h"
|
#include "../client/protocols/protocols_defs.h"
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "../client/platforms/windows/daemon/windowsdaemon.h"
|
#include "../client/platforms/windows/daemon/windowsdaemon.h"
|
||||||
|
|
@ -209,7 +210,7 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
|
||||||
if (splitTunnelType == 0) {
|
if (splitTunnelType == 0) {
|
||||||
blockAll = true;
|
blockAll = true;
|
||||||
allowNets = true;
|
allowNets = true;
|
||||||
allownets.append(configStr.value(amnezia::config_key::hostName).toString());
|
allownets.append(configStr.value("vpnServer").toString());
|
||||||
} else if (splitTunnelType == 1) {
|
} else if (splitTunnelType == 1) {
|
||||||
blockNets = true;
|
blockNets = true;
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
|
|
@ -218,7 +219,7 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
|
||||||
} else if (splitTunnelType == 2) {
|
} else if (splitTunnelType == 2) {
|
||||||
blockAll = true;
|
blockAll = true;
|
||||||
allowNets = true;
|
allowNets = true;
|
||||||
allownets.append(configStr.value(amnezia::config_key::hostName).toString());
|
allownets.append(configStr.value("vpnServer").toString());
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
allownets.append(v.toString());
|
allownets.append(v.toString());
|
||||||
}
|
}
|
||||||
|
|
@ -329,7 +330,7 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.m_excludedAddresses.append(configStr.value(amnezia::config_key::hostName).toString());
|
config.m_excludedAddresses.append(configStr.value("vpnServer").toString());
|
||||||
if (splitTunnelType == 2) {
|
if (splitTunnelType == 2) {
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
QString ipRange = v.toString();
|
QString ipRange = v.toString();
|
||||||
|
|
@ -351,7 +352,6 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
||||||
|
|
||||||
WindowsDaemon::instance()->prepareActivation(config, inetAdapterIndex);
|
WindowsDaemon::instance()->prepareActivation(config, inetAdapterIndex);
|
||||||
WindowsDaemon::instance()->activateSplitTunnel(config, vpnAdapterIndex);
|
WindowsDaemon::instance()->activateSplitTunnel(config, vpnAdapterIndex);
|
||||||
return true;
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,10 @@
|
||||||
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "ipcserverprocess.h"
|
#include "ipcserverprocess.h"
|
||||||
|
#include "ipctun2socksprocess.h"
|
||||||
|
|
||||||
#include "rep_ipc_interface_source.h"
|
#include "rep_ipc_interface_source.h"
|
||||||
|
#include "rep_ipc_process_tun2socks_source.h"
|
||||||
|
|
||||||
class IpcServer : public IpcInterfaceSource
|
class IpcServer : public IpcInterfaceSource
|
||||||
{
|
{
|
||||||
|
|
@ -44,10 +46,12 @@ private:
|
||||||
ProcessDescriptor (QObject *parent = nullptr) {
|
ProcessDescriptor (QObject *parent = nullptr) {
|
||||||
serverNode = QSharedPointer<QRemoteObjectHost>(new QRemoteObjectHost(parent));
|
serverNode = QSharedPointer<QRemoteObjectHost>(new QRemoteObjectHost(parent));
|
||||||
ipcProcess = QSharedPointer<IpcServerProcess>(new IpcServerProcess(parent));
|
ipcProcess = QSharedPointer<IpcServerProcess>(new IpcServerProcess(parent));
|
||||||
|
tun2socksProcess = QSharedPointer<IpcProcessTun2Socks>(new IpcProcessTun2Socks(parent));
|
||||||
localServer = QSharedPointer<QLocalServer>(new QLocalServer(parent));
|
localServer = QSharedPointer<QLocalServer>(new QLocalServer(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<IpcServerProcess> ipcProcess;
|
QSharedPointer<IpcServerProcess> ipcProcess;
|
||||||
|
QSharedPointer<IpcProcessTun2Socks> tun2socksProcess;
|
||||||
QSharedPointer<QRemoteObjectHost> serverNode;
|
QSharedPointer<QRemoteObjectHost> serverNode;
|
||||||
QSharedPointer<QLocalServer> localServer;
|
QSharedPointer<QLocalServer> localServer;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
74
ipc/ipctun2socksprocess.cpp
Normal file
74
ipc/ipctun2socksprocess.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
#include "ipctun2socksprocess.h"
|
||||||
|
#include "ipc.h"
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "../protocols/protocols_defs.h"
|
||||||
|
|
||||||
|
#ifndef Q_OS_IOS
|
||||||
|
|
||||||
|
IpcProcessTun2Socks::IpcProcessTun2Socks(QObject *parent) :
|
||||||
|
IpcProcessTun2SocksSource(parent),
|
||||||
|
m_t2sProcess(QSharedPointer<QProcess>(new QProcess()))
|
||||||
|
{
|
||||||
|
connect(m_t2sProcess.data(), &QProcess::stateChanged, this, &IpcProcessTun2Socks::stateChanged);
|
||||||
|
qDebug() << "IpcProcessTun2Socks::IpcProcessTun2Socks()";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcProcessTun2Socks::~IpcProcessTun2Socks()
|
||||||
|
{
|
||||||
|
qDebug() << "IpcProcessTun2Socks::~IpcProcessTun2Socks()";
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcProcessTun2Socks::start()
|
||||||
|
{
|
||||||
|
qDebug() << "IpcProcessTun2Socks::start()";
|
||||||
|
m_t2sProcess->setProgram(amnezia::permittedProcessPath(static_cast<amnezia::PermittedProcess>(amnezia::PermittedProcess::Tun2Socks)));
|
||||||
|
QString XrayConStr = "socks5://127.0.0.1:10808";
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up",
|
||||||
|
QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255")
|
||||||
|
.arg(amnezia::protocols::xray::defaultLocalAddr)});
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr});
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
QStringList arguments({"-device", "utun22", "-proxy", XrayConStr});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_t2sProcess->setArguments(arguments);
|
||||||
|
|
||||||
|
Utils::killProcessByName(m_t2sProcess->program());
|
||||||
|
m_t2sProcess->start();
|
||||||
|
|
||||||
|
connect(m_t2sProcess.data(), &QProcess::readyReadStandardOutput, this, [this]() {
|
||||||
|
QString line = m_t2sProcess.data()->readAllStandardOutput();
|
||||||
|
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://127.0.0.1")) {
|
||||||
|
emit setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_t2sProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
|
qDebug().noquote() << "tun2socks finished, exitCode, exiStatus" << exitCode << exitStatus;
|
||||||
|
emit setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
if (exitStatus != QProcess::NormalExit){
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
if (exitCode !=0 ){
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_t2sProcess->start();
|
||||||
|
m_t2sProcess->waitForStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcProcessTun2Socks::stop()
|
||||||
|
{
|
||||||
|
qDebug() << "IpcProcessTun2Socks::stop()";
|
||||||
|
m_t2sProcess->close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
52
ipc/ipctun2socksprocess.h
Normal file
52
ipc/ipctun2socksprocess.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef IPCTUN2SOCKSPROCESS_H
|
||||||
|
#define IPCTUN2SOCKSPROCESS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#ifndef Q_OS_IOS
|
||||||
|
#include "rep_ipc_process_tun2socks_source.h"
|
||||||
|
|
||||||
|
namespace Vpn
|
||||||
|
{
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum ConnectionState {
|
||||||
|
Unknown,
|
||||||
|
Disconnected,
|
||||||
|
Preparing,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
Disconnecting,
|
||||||
|
Reconnecting,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(ConnectionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IpcProcessTun2Socks : public IpcProcessTun2SocksSource
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit IpcProcessTun2Socks(QObject *parent = nullptr);
|
||||||
|
virtual ~IpcProcessTun2Socks();
|
||||||
|
|
||||||
|
void start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedPointer<QProcess> m_t2sProcess;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
class IpcProcessTun2Socks : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit IpcProcessTun2Socks(QObject *parent = nullptr);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // IPCTUN2SOCKSPROCESS_H
|
||||||
|
|
@ -18,6 +18,7 @@ set(HEADERS
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc.h
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipctun2socksprocess.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/localserver.h
|
${CMAKE_CURRENT_LIST_DIR}/localserver.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.h
|
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/router.h
|
${CMAKE_CURRENT_LIST_DIR}/router.h
|
||||||
|
|
@ -30,6 +31,7 @@ set(SOURCES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../client/core/networkUtilities.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../client/core/networkUtilities.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipctun2socksprocess.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/localserver.cpp
|
${CMAKE_CURRENT_LIST_DIR}/localserver.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
||||||
|
|
@ -279,6 +281,7 @@ endif()
|
||||||
|
|
||||||
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_interface.rep)
|
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_interface.rep)
|
||||||
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_interface.rep)
|
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_interface.rep)
|
||||||
|
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_tun2socks.rep)
|
||||||
|
|
||||||
# copy deploy artifacts required to run the application to the debug build folder
|
# copy deploy artifacts required to run the application to the debug build folder
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
|
||||||
if (!m_isRemotingEnabled) {
|
if (!m_isRemotingEnabled) {
|
||||||
m_isRemotingEnabled = true;
|
m_isRemotingEnabled = true;
|
||||||
m_serverNode.enableRemoting(&m_ipcServer);
|
m_serverNode.enableRemoting(&m_ipcServer);
|
||||||
|
m_serverNode.enableRemoting(&m_tun2socks);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ public:
|
||||||
~LocalServer();
|
~LocalServer();
|
||||||
QSharedPointer<QLocalServer> m_server;
|
QSharedPointer<QLocalServer> m_server;
|
||||||
IpcServer m_ipcServer;
|
IpcServer m_ipcServer;
|
||||||
|
IpcProcessTun2Socks m_tun2socks;
|
||||||
QRemoteObjectHost m_serverNode;
|
QRemoteObjectHost m_serverNode;
|
||||||
bool m_isRemotingEnabled = false;
|
bool m_isRemotingEnabled = false;
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue