From 8948601caa4fed80573ff4946b2632ee82cf713a Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 17 Sep 2024 15:11:14 +0400 Subject: [PATCH 01/11] bugfix: fixed awg/wg persistentKeepAlive variable type --- client/platforms/ios/WGConfig.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/platforms/ios/WGConfig.swift b/client/platforms/ios/WGConfig.swift index e3b67efe..0647abea 100644 --- a/client/platforms/ios/WGConfig.swift +++ b/client/platforms/ios/WGConfig.swift @@ -15,7 +15,7 @@ struct WGConfig: Decodable { let serverPublicKey: String let presharedKey: String? var allowedIPs: [String] - var persistentKeepAlive: String + var persistentKeepAlive: Int let splitTunnelType: Int let splitTunnelSites: [String] From 6f94f4646adf6c12d8b9292104ac2f7bab1e66f3 Mon Sep 17 00:00:00 2001 From: Pokamest Nikak Date: Thu, 19 Sep 2024 11:18:40 +0100 Subject: [PATCH 02/11] Fix Xray connection timeout for Windows --- client/protocols/xrayprotocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 client/protocols/xrayprotocol.cpp diff --git a/client/protocols/xrayprotocol.cpp b/client/protocols/xrayprotocol.cpp old mode 100644 new mode 100755 index a45be887..41e955b0 --- a/client/protocols/xrayprotocol.cpp +++ b/client/protocols/xrayprotocol.cpp @@ -146,7 +146,7 @@ ErrorCode XrayProtocol::startTun2Sock() IpcClient::Interface()->updateResolvers("utun22", dnsAddr); #endif #ifdef Q_OS_WINDOWS - QThread::msleep(15000); + QThread::msleep(7000); #endif #ifdef Q_OS_LINUX QThread::msleep(1000); From 138e6f70a47d09caabbb1d65eeb0c56f13471cef Mon Sep 17 00:00:00 2001 From: albexk Date: Thu, 19 Sep 2024 13:31:59 +0300 Subject: [PATCH 03/11] Fix domain name resolution for XRay --- CMakeLists.txt | 4 ++-- .../android/utils/src/main/kotlin/net/NetworkUtils.kt | 2 +- client/android/xray/src/main/kotlin/Xray.kt | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c2f7bf6..b84c25f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.8.0.4 +project(${PROJECT} VERSION 4.8.0.5 DESCRIPTION "AmneziaVPN" HOMEPAGE_URL "https://amnezia.org/" ) @@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d") set(RELEASE_DATE "${CURRENT_DATE}") set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) -set(APP_ANDROID_VERSION_CODE 60) +set(APP_ANDROID_VERSION_CODE 61) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") diff --git a/client/android/utils/src/main/kotlin/net/NetworkUtils.kt b/client/android/utils/src/main/kotlin/net/NetworkUtils.kt index 5c680d31..784aa352 100644 --- a/client/android/utils/src/main/kotlin/net/NetworkUtils.kt +++ b/client/android/utils/src/main/kotlin/net/NetworkUtils.kt @@ -60,7 +60,7 @@ private val parseNumericAddressCompat: (String) -> InetAddress = internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6 .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) { hostAddress!! } else { diff --git a/client/android/xray/src/main/kotlin/Xray.kt b/client/android/xray/src/main/kotlin/Xray.kt index ec22a4bd..6e37c9c2 100644 --- a/client/android/xray/src/main/kotlin/Xray.kt +++ b/client/android/xray/src/main/kotlin/Xray.kt @@ -17,6 +17,7 @@ import org.amnezia.vpn.protocol.xray.libXray.Logger import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.net.InetNetwork +import org.amnezia.vpn.util.net.ip import org.amnezia.vpn.util.net.parseInetAddress import org.json.JSONObject @@ -61,7 +62,15 @@ class Xray : Protocol() { .put("loglevel", "warning") .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 isRunning = true } From b881d92a800f94aeedbf24ed1d8ff7caf522e578 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Thu, 19 Sep 2024 15:52:58 +0400 Subject: [PATCH 04/11] bugfix: returned awg/wg persistentKeepAlive variable type to string --- client/configurators/wireguard_configurator.cpp | 2 +- client/platforms/ios/WGConfig.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index 0d083742..3f96e74c 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -199,7 +199,7 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials jConfig[config_key::server_pub_key] = connData.serverPubKey; 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" }; jConfig[config_key::allowed_ips] = allowedIps; diff --git a/client/platforms/ios/WGConfig.swift b/client/platforms/ios/WGConfig.swift index 0647abea..e3b67efe 100644 --- a/client/platforms/ios/WGConfig.swift +++ b/client/platforms/ios/WGConfig.swift @@ -15,7 +15,7 @@ struct WGConfig: Decodable { let serverPublicKey: String let presharedKey: String? var allowedIPs: [String] - var persistentKeepAlive: Int + var persistentKeepAlive: String let splitTunnelType: Int let splitTunnelSites: [String] From 864879058322bfbbdf89ef8bd60a02a4e227d9d0 Mon Sep 17 00:00:00 2001 From: Iurii Egorov Date: Thu, 19 Sep 2024 18:47:20 +0300 Subject: [PATCH 05/11] Fix iOS build on GHA --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e8ad8fdf..d9138516 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -181,7 +181,7 @@ jobs: - name: 'Install go' uses: actions/setup-go@v5 with: - go-version: '1.20' + go-version: '1.22.1' cache: false - name: 'Setup gomobile' From 8735eee662d663f1d11a776ef5786d4f2ec465c6 Mon Sep 17 00:00:00 2001 From: albexk Date: Thu, 19 Sep 2024 23:38:58 +0300 Subject: [PATCH 06/11] Exclude protocol libraries from loading at application startup --- client/android/cloak/src/main/kotlin/Cloak.kt | 6 ++ .../amnezia/vpn/protocol/openvpn/OpenVpn.kt | 6 +- .../protocolApi/src/main/kotlin/Exceptions.kt | 1 - .../protocolApi/src/main/kotlin/Protocol.kt | 54 --------------- client/android/res/values/libs.xml | 1 - .../src/org/amnezia/vpn/AmneziaActivity.kt | 13 ++++ .../src/org/amnezia/vpn/AmneziaVpnService.kt | 2 +- .../utils/src/main/kotlin/LibraryLoader.kt | 66 +++++++++++++++++++ .../vpn/protocol/wireguard/Wireguard.kt | 2 +- 9 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 client/android/utils/src/main/kotlin/LibraryLoader.kt diff --git a/client/android/cloak/src/main/kotlin/Cloak.kt b/client/android/cloak/src/main/kotlin/Cloak.kt index 18a5e6c7..d408fb19 100644 --- a/client/android/cloak/src/main/kotlin/Cloak.kt +++ b/client/android/cloak/src/main/kotlin/Cloak.kt @@ -3,10 +3,16 @@ package org.amnezia.vpn.protocol.cloak import android.util.Base64 import net.openvpn.ovpn3.ClientAPI_Config import org.amnezia.vpn.protocol.openvpn.OpenVpn +import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary import org.json.JSONObject class Cloak : OpenVpn() { + override fun internalInit() { + super.internalInit() + if (!isInitialized) loadSharedLibrary(context, "ck-ovpn-plugin") + } + override fun parseConfig(config: JSONObject): ClientAPI_Config { val openVpnConfig = ClientAPI_Config() diff --git a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt index fa0e19f1..22fe35cd 100644 --- a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt +++ b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt @@ -11,6 +11,7 @@ import org.amnezia.vpn.protocol.Protocol import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED import org.amnezia.vpn.protocol.Statistics 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.getLocalNetworks import org.amnezia.vpn.util.net.parseInetAddress @@ -34,7 +35,10 @@ open class OpenVpn : Protocol() { } override fun internalInit() { - if (!isInitialized) loadSharedLibrary(context, "ovpn3") + if (!isInitialized) { + loadSharedLibrary(context, "ovpn3") + loadSharedLibrary(context, "ovpnutil") + } if (this::scope.isInitialized) { scope.cancel() } diff --git a/client/android/protocolApi/src/main/kotlin/Exceptions.kt b/client/android/protocolApi/src/main/kotlin/Exceptions.kt index 739a327c..b80648b0 100644 --- a/client/android/protocolApi/src/main/kotlin/Exceptions.kt +++ b/client/android/protocolApi/src/main/kotlin/Exceptions.kt @@ -2,7 +2,6 @@ package org.amnezia.vpn.protocol 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 VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause) diff --git a/client/android/protocolApi/src/main/kotlin/Protocol.kt b/client/android/protocolApi/src/main/kotlin/Protocol.kt index 24cbc595..b5c382be 100644 --- a/client/android/protocolApi/src/main/kotlin/Protocol.kt +++ b/client/android/protocolApi/src/main/kotlin/Protocol.kt @@ -158,60 +158,6 @@ abstract class Protocol { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) vpnBuilder.setMetered(false) } - - companion object { - private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean { - Log.d(TAG, "Extracting library: $libraryName") - val apks = hashSetOf() - 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) diff --git a/client/android/res/values/libs.xml b/client/android/res/values/libs.xml index fe63866f..3ccf1d80 100644 --- a/client/android/res/values/libs.xml +++ b/client/android/res/values/libs.xml @@ -3,7 +3,6 @@ - diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt index 9d1c31cb..d5026425 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt @@ -43,6 +43,7 @@ import kotlinx.coroutines.withContext import org.amnezia.vpn.protocol.getStatistics import org.amnezia.vpn.protocol.getStatus import org.amnezia.vpn.qt.QtAndroidController +import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.Prefs import org.json.JSONException @@ -158,6 +159,7 @@ class AmneziaActivity : QtActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d(TAG, "Create Amnezia activity: $intent") + loadLibs() window.apply { addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) statusBarColor = getColor(R.color.black) @@ -179,6 +181,17 @@ class AmneziaActivity : QtActivity() { runBlocking { vpnProto = proto.await() } } + private fun loadLibs() { + listOf( + "rsapss", + "crypto_3", + "ssl_3", + "ssh" + ).forEach { + loadSharedLibrary(this.applicationContext, it) + } + } + private fun registerBroadcastReceivers() { notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { registerBroadcastReceiver( diff --git a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt index 54330861..6a7da7c7 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt @@ -40,7 +40,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout 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.CONNECTING 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.VpnStartException import org.amnezia.vpn.protocol.putStatus +import org.amnezia.vpn.util.LoadLibraryException import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.Prefs import org.amnezia.vpn.util.net.NetworkState diff --git a/client/android/utils/src/main/kotlin/LibraryLoader.kt b/client/android/utils/src/main/kotlin/LibraryLoader.kt new file mode 100644 index 00000000..f1c6465e --- /dev/null +++ b/client/android/utils/src/main/kotlin/LibraryLoader.kt @@ -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() + 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) diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index c32ab8c2..31e7f9be 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -3,7 +3,6 @@ package org.amnezia.vpn.protocol.wireguard import android.net.VpnService.Builder import java.io.IOException import java.util.Locale -import java.util.TreeMap import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay 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.Statistics import org.amnezia.vpn.protocol.VpnStartException +import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.asSequence import org.amnezia.vpn.util.net.InetEndpoint From a22a9448caa81d44cd480bbc73b28d2c65afdc7e Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Fri, 20 Sep 2024 04:12:22 -0700 Subject: [PATCH 07/11] Some XRay improvements (#1075) --- client/CMakeLists.txt | 1 + client/core/ipcclient.cpp | 16 ++- client/core/ipcclient.h | 5 + client/protocols/openvpnprotocol.cpp | 8 +- client/protocols/xrayprotocol.cpp | 185 +++++++++++---------------- client/protocols/xrayprotocol.h | 3 +- ipc/ipc_interface.rep | 1 - ipc/ipc_process_interface.rep | 1 - ipc/ipc_process_tun2socks.rep | 11 ++ ipc/ipcserver.cpp | 8 +- ipc/ipcserver.h | 4 + ipc/ipctun2socksprocess.cpp | 74 +++++++++++ ipc/ipctun2socksprocess.h | 52 ++++++++ service/server/CMakeLists.txt | 3 + service/server/localserver.cpp | 1 + service/server/localserver.h | 1 + 16 files changed, 252 insertions(+), 122 deletions(-) create mode 100644 ipc/ipc_process_tun2socks.rep create mode 100644 ipc/ipctun2socksprocess.cpp create mode 100644 ipc/ipctun2socksprocess.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 4d0c1c2a..2de5db48 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -61,6 +61,7 @@ qt_add_executable(${PROJECT} MANUAL_FINALIZATION) 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_process_interface.rep) + qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep) endif() qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc) diff --git a/client/core/ipcclient.cpp b/client/core/ipcclient.cpp index 3e364452..b44da1bf 100644 --- a/client/core/ipcclient.cpp +++ b/client/core/ipcclient.cpp @@ -29,6 +29,12 @@ QSharedPointer IpcClient::Interface() return Instance()->m_ipcClient; } +QSharedPointer IpcClient::InterfaceTun2Socks() +{ + if (!Instance()) return nullptr; + return Instance()->m_Tun2SocksClient; +} + bool IpcClient::init(IpcClient *instance) { m_instance = instance; @@ -44,6 +50,12 @@ bool IpcClient::init(IpcClient *instance) qWarning() << "IpcClient replica is not connected!"; } + Instance()->m_Tun2SocksClient.reset(Instance()->m_ClientNode.acquire()); + 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](){ @@ -51,16 +63,16 @@ bool IpcClient::init(IpcClient *instance) }); Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl()); - Instance()->m_localSocket->waitForConnected(); if (!Instance()->m_ipcClient) { qDebug() << "IpcClient::init failed"; return false; } + qDebug() << "IpcClient::init succeed"; - return Instance()->m_ipcClient->isReplicaValid(); + return (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid()); } QSharedPointer IpcClient::CreatePrivilegedProcess() diff --git a/client/core/ipcclient.h b/client/core/ipcclient.h index ab5d750a..ad2e6b6e 100644 --- a/client/core/ipcclient.h +++ b/client/core/ipcclient.h @@ -6,6 +6,7 @@ #include "ipc.h" #include "rep_ipc_interface_replica.h" +#include "rep_ipc_process_tun2socks_replica.h" #include "privileged_process.h" @@ -18,6 +19,7 @@ public: static IpcClient *Instance(); static bool init(IpcClient *instance); static QSharedPointer Interface(); + static QSharedPointer InterfaceTun2Socks(); static QSharedPointer CreatePrivilegedProcess(); bool isSocketConnected() const; @@ -28,8 +30,11 @@ private: ~IpcClient() override; QRemoteObjectNode m_ClientNode; + QRemoteObjectNode m_Tun2SocksNode; QSharedPointer m_ipcClient; QPointer m_localSocket; + QPointer m_tun2socksSocket; + QSharedPointer m_Tun2SocksClient; struct ProcessDescriptor { ProcessDescriptor () { diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 04a18327..4c2feb52 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -6,6 +6,7 @@ #include #include +#include "core/networkUtilities.h" #include "logger.h" #include "openvpnprotocol.h" #include "utilities.h" @@ -127,7 +128,6 @@ void OpenVpnProtocol::sendManagementCommand(const QString &command) uint OpenVpnProtocol::selectMgmtPort() { - for (int i = 0; i < 100; ++i) { quint32 port = QRandomGenerator::global()->generate(); port = (double)(65000 - 15001) * port / UINT32_MAX + 15001; @@ -137,7 +137,6 @@ uint OpenVpnProtocol::selectMgmtPort() if (ok) return port; } - return m_managementPort; } @@ -343,7 +342,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) } m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); 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); } } @@ -352,6 +352,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) // killSwitch toggle 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); } #endif diff --git a/client/protocols/xrayprotocol.cpp b/client/protocols/xrayprotocol.cpp index 41e955b0..2dfbcc21 100755 --- a/client/protocols/xrayprotocol.cpp +++ b/client/protocols/xrayprotocol.cpp @@ -17,6 +17,7 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent): m_routeGateway = NetworkUtilities::getGatewayAndIface(); m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr; m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr; + m_t2sProcess = IpcClient::InterfaceTun2Socks(); } XrayProtocol::~XrayProtocol() @@ -65,7 +66,7 @@ ErrorCode XrayProtocol::start() }); connect(&m_xrayProcess, QOverload::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); if (exitStatus != QProcess::NormalExit) { emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed); @@ -91,116 +92,80 @@ ErrorCode XrayProtocol::start() ErrorCode XrayProtocol::startTun2Sock() { - if (!QFileInfo::exists(Utils::tun2socksPath())) { - 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 - 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 -#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(), &PrivilegedProcess::errorOccurred, - [&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; }); - - connect(m_t2sProcess.data(), &PrivilegedProcess::stateChanged, - [&](QProcess::ProcessState newState) { - qDebug() << "PrivilegedProcess stateChanged" << newState; - if (newState == QProcess::Running) - { - setConnectionState(Vpn::ConnectionState::Connecting); - QList dnsAddr; - dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString())); - dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString())); - -#ifdef Q_OS_MACOS - QThread::msleep(5000); - IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr); - IpcClient::Interface()->updateResolvers("utun22", dnsAddr); -#endif -#ifdef Q_OS_WINDOWS - QThread::msleep(7000); -#endif -#ifdef Q_OS_LINUX - QThread::msleep(1000); - IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr); - IpcClient::Interface()->updateResolvers("tun2", dnsAddr); -#endif -#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - // killSwitch toggle - if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { - IpcClient::Interface()->enableKillSwitch(m_configData, 0); - } -#endif - if (m_routeMode == 0) { - IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1"); - IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1"); - IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress); - } - IpcClient::Interface()->StopRoutingIpv6(); -#ifdef Q_OS_WIN - IpcClient::Interface()->updateResolvers("tun2", dnsAddr); - QList netInterfaces = QNetworkInterface::allInterfaces(); - for (int i = 0; i < netInterfaces.size(); i++) { - for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) - { - // killSwitch toggle - if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { - if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { - IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); - } - m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); - m_configData.insert("vpnGateway", m_vpnGateway); - m_configData.insert("vpnServer", m_remoteAddress); - IpcClient::Interface()->enablePeerTraffic(m_configData); - } - } - } -#endif - setConnectionState(Vpn::ConnectionState::Connected); - } - }); - - -#if !defined(Q_OS_MACOS) - connect(m_t2sProcess.data(), &PrivilegedProcess::finished, this, - [&]() { - setConnectionState(Vpn::ConnectionState::Disconnected); - IpcClient::Interface()->deleteTun("tun2"); - IpcClient::Interface()->StartRoutingIpv6(); - IpcClient::Interface()->clearSavedRoutes(); - }); -#endif - m_t2sProcess->start(); +#ifdef Q_OS_WIN + m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress))); +#endif + + connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::stateChanged, this, + [&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; }); + + connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, + [&](int vpnState) { + qDebug() << "PrivilegedProcess setConnectionState " << vpnState; + if (vpnState == Vpn::ConnectionState::Connected) + { + setConnectionState(Vpn::ConnectionState::Connecting); + QList dnsAddr; + dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString())); + dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString())); +#ifdef Q_OS_WIN + QThread::msleep(8000); +#endif +#ifdef Q_OS_MACOS + QThread::msleep(5000); + IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr); + IpcClient::Interface()->updateResolvers("utun22", dnsAddr); +#endif +#ifdef Q_OS_LINUX + QThread::msleep(1000); + IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr); + IpcClient::Interface()->updateResolvers("tun2", dnsAddr); +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + // killSwitch toggle + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + m_configData.insert("vpnServer", m_remoteAddress); + IpcClient::Interface()->enableKillSwitch(m_configData, 0); + } +#endif + if (m_routeMode == 0) { + IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1"); + IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1"); + IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress); + } + IpcClient::Interface()->StopRoutingIpv6(); +#ifdef Q_OS_WIN + IpcClient::Interface()->updateResolvers("tun2", dnsAddr); + QList netInterfaces = QNetworkInterface::allInterfaces(); + for (int i = 0; i < netInterfaces.size(); i++) { + for (int j = 0; j < netInterfaces.at(i).addressEntries().size(); j++) + { + // killSwitch toggle + if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); + } + m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); + m_configData.insert("vpnGateway", m_vpnGateway); + m_configData.insert("vpnServer", m_remoteAddress); + IpcClient::Interface()->enablePeerTraffic(m_configData); + } + } + } +#endif + setConnectionState(Vpn::ConnectionState::Connected); + } +#if !defined(Q_OS_MACOS) + if (vpnState == Vpn::ConnectionState::Disconnected) { + setConnectionState(Vpn::ConnectionState::Disconnected); + IpcClient::Interface()->deleteTun("tun2"); + IpcClient::Interface()->StartRoutingIpv6(); + IpcClient::Interface()->clearSavedRoutes(); + } +#endif + }); return ErrorCode::NoError; } @@ -214,7 +179,7 @@ void XrayProtocol::stop() qDebug() << "XrayProtocol::stop()"; m_xrayProcess.terminate(); if (m_t2sProcess) { - m_t2sProcess->close(); + m_t2sProcess->stop(); } #ifdef Q_OS_WIN diff --git a/client/protocols/xrayprotocol.h b/client/protocols/xrayprotocol.h index c1d62897..ee632333 100644 --- a/client/protocols/xrayprotocol.h +++ b/client/protocols/xrayprotocol.h @@ -34,9 +34,10 @@ private: QString m_secondaryDNS; #ifndef Q_OS_IOS QProcess m_xrayProcess; - QSharedPointer m_t2sProcess; + QSharedPointer m_t2sProcess; #endif QTemporaryFile m_xrayCfgFile; + }; #endif // XRAYPROTOCOL_H diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 5baf9c33..c0f031fe 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -7,7 +7,6 @@ class IpcInterface { SLOT( int createPrivilegedProcess() ); // return local pid - //SIGNAL(sendMessage(const QByteArray &message)); // Route functions SLOT( int routeAddList(const QString &gw, const QStringList &ips) ); diff --git a/ipc/ipc_process_interface.rep b/ipc/ipc_process_interface.rep index ba42332c..6b3bb654 100644 --- a/ipc/ipc_process_interface.rep +++ b/ipc/ipc_process_interface.rep @@ -3,7 +3,6 @@ class IpcProcessInterface { - //SLOT( start(const QString &program, const QStringList &args) ); SLOT( start() ); SLOT( close() ); diff --git a/ipc/ipc_process_tun2socks.rep b/ipc/ipc_process_tun2socks.rep new file mode 100644 index 00000000..e355035e --- /dev/null +++ b/ipc/ipc_process_tun2socks.rep @@ -0,0 +1,11 @@ +#include +#include + +class IpcProcessTun2Socks +{ + SLOT( start() ); + SLOT( stop() ); + + SIGNAL( setConnectionState(int state) ); + SIGNAL( stateChanged(QProcess::ProcessState newState) ); +}; diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index cee2c398..bb8a4182 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -8,6 +8,7 @@ #include "logger.h" #include "router.h" +#include "../core/networkUtilities.h" #include "../client/protocols/protocols_defs.h" #ifdef Q_OS_WIN #include "../client/platforms/windows/daemon/windowsdaemon.h" @@ -209,7 +210,7 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd if (splitTunnelType == 0) { blockAll = true; allowNets = true; - allownets.append(configStr.value(amnezia::config_key::hostName).toString()); + allownets.append(configStr.value("vpnServer").toString()); } else if (splitTunnelType == 1) { blockNets = true; for (auto v : splitTunnelSites) { @@ -218,7 +219,7 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd } else if (splitTunnelType == 2) { blockAll = true; allowNets = true; - allownets.append(configStr.value(amnezia::config_key::hostName).toString()); + allownets.append(configStr.value("vpnServer").toString()); for (auto v : splitTunnelSites) { 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) { for (auto v : splitTunnelSites) { QString ipRange = v.toString(); @@ -351,7 +352,6 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr) WindowsDaemon::instance()->prepareActivation(config, inetAdapterIndex); WindowsDaemon::instance()->activateSplitTunnel(config, vpnAdapterIndex); - return true; #endif return true; } diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 74f88d0f..9810046b 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -9,8 +9,10 @@ #include "ipc.h" #include "ipcserverprocess.h" +#include "ipctun2socksprocess.h" #include "rep_ipc_interface_source.h" +#include "rep_ipc_process_tun2socks_source.h" class IpcServer : public IpcInterfaceSource { @@ -44,10 +46,12 @@ private: ProcessDescriptor (QObject *parent = nullptr) { serverNode = QSharedPointer(new QRemoteObjectHost(parent)); ipcProcess = QSharedPointer(new IpcServerProcess(parent)); + tun2socksProcess = QSharedPointer(new IpcProcessTun2Socks(parent)); localServer = QSharedPointer(new QLocalServer(parent)); } QSharedPointer ipcProcess; + QSharedPointer tun2socksProcess; QSharedPointer serverNode; QSharedPointer localServer; }; diff --git a/ipc/ipctun2socksprocess.cpp b/ipc/ipctun2socksprocess.cpp new file mode 100644 index 00000000..ffcb1bcd --- /dev/null +++ b/ipc/ipctun2socksprocess.cpp @@ -0,0 +1,74 @@ +#include "ipctun2socksprocess.h" +#include "ipc.h" +#include +#include + +#include "../protocols/protocols_defs.h" + +#ifndef Q_OS_IOS + +IpcProcessTun2Socks::IpcProcessTun2Socks(QObject *parent) : + IpcProcessTun2SocksSource(parent), + m_t2sProcess(QSharedPointer(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::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::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 diff --git a/ipc/ipctun2socksprocess.h b/ipc/ipctun2socksprocess.h new file mode 100644 index 00000000..8ce9be1a --- /dev/null +++ b/ipc/ipctun2socksprocess.h @@ -0,0 +1,52 @@ +#ifndef IPCTUN2SOCKSPROCESS_H +#define IPCTUN2SOCKSPROCESS_H + +#include + +#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 m_t2sProcess; +}; + +#else +class IpcProcessTun2Socks : public QObject +{ + Q_OBJECT + +public: + explicit IpcProcessTun2Socks(QObject *parent = nullptr); +}; +#endif + +#endif // IPCTUN2SOCKSPROCESS_H diff --git a/service/server/CMakeLists.txt b/service/server/CMakeLists.txt index c41e57f5..0f101087 100644 --- a/service/server/CMakeLists.txt +++ b/service/server/CMakeLists.txt @@ -18,6 +18,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc.h ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.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}/../../common/logger/logger.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}/../../ipc/ipcserver.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}/../../common/logger/logger.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_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 if(WIN32) diff --git a/service/server/localserver.cpp b/service/server/localserver.cpp index 3e1b0954..8a5079cb 100644 --- a/service/server/localserver.cpp +++ b/service/server/localserver.cpp @@ -37,6 +37,7 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent), if (!m_isRemotingEnabled) { m_isRemotingEnabled = true; m_serverNode.enableRemoting(&m_ipcServer); + m_serverNode.enableRemoting(&m_tun2socks); } }); diff --git a/service/server/localserver.h b/service/server/localserver.h index 4a6648a5..3c565d3b 100644 --- a/service/server/localserver.h +++ b/service/server/localserver.h @@ -38,6 +38,7 @@ public: ~LocalServer(); QSharedPointer m_server; IpcServer m_ipcServer; + IpcProcessTun2Socks m_tun2socks; QRemoteObjectHost m_serverNode; bool m_isRemotingEnabled = false; #ifdef Q_OS_LINUX From 504862c2b8a31183af5b170e1d966117450482a3 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Fri, 20 Sep 2024 15:36:20 +0400 Subject: [PATCH 08/11] bugfix: fixed drawer size to pageHome on first startup --- client/ui/qml/main2.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml index a5a47e2c..fb99559f 100644 --- a/client/ui/qml/main2.qml +++ b/client/ui/qml/main2.qml @@ -80,7 +80,8 @@ Window { } PageStart { - anchors.fill: parent + width: root.width + height: root.height } Item { From c681611102c0a371c694be79fe25e18694f006a7 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 20 Sep 2024 13:08:28 +0100 Subject: [PATCH 09/11] Bump version to 4.8.1.0 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b84c25f6..79b0c18c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.8.0.5 +project(${PROJECT} VERSION 4.8.1.0 DESCRIPTION "AmneziaVPN" HOMEPAGE_URL "https://amnezia.org/" ) @@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d") set(RELEASE_DATE "${CURRENT_DATE}") set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) -set(APP_ANDROID_VERSION_CODE 61) +set(APP_ANDROID_VERSION_CODE 62) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") From 268adfb0a17465f4b02872d592432e9e82076b75 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sun, 22 Sep 2024 23:05:07 +0500 Subject: [PATCH 10/11] bugfix: fixed parameter handling for native wg obfuscation --- client/platforms/ios/ios_controller.mm | 14 +++++++++++ client/protocols/protocols_defs.h | 1 + client/ui/controllers/importController.cpp | 28 ++++++++++++---------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index 6abae584..85fb50b7 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -499,6 +499,20 @@ bool IosController::setupWireGuard() 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); QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact)); diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index 56be0d7d..865edae4 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -65,6 +65,7 @@ namespace amnezia constexpr char last_config[] = "last_config"; constexpr char isThirdPartyConfig[] = "isThirdPartyConfig"; + constexpr char isObfuscationEnabled[] = "isObfuscationEnabled"; constexpr char junkPacketCount[] = "Jc"; constexpr char junkPacketMinSize[] = "Jmin"; diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 32170fb6..261551ea 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -242,24 +242,26 @@ void ImportController::processNativeWireGuardConfig() auto containers = m_config.value(config_key::containers).toArray(); if (!containers.isEmpty()) { auto container = containers.at(0).toObject(); - auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject(); - auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object(); + auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject(); + auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object(); QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5)); QString junkPacketMinSize = QString::number(10); QString junkPacketMaxSize = QString::number(50); - protocolConfig[config_key::junkPacketCount] = junkPacketCount; - protocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize; - protocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize; - protocolConfig[config_key::initPacketJunkSize] = "0"; - protocolConfig[config_key::responsePacketJunkSize] = "0"; - protocolConfig[config_key::initPacketMagicHeader] = "1"; - protocolConfig[config_key::responsePacketMagicHeader] = "2"; - protocolConfig[config_key::underloadPacketMagicHeader] = "3"; - protocolConfig[config_key::transportPacketMagicHeader] = "4"; + clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount; + clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize; + clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize; + clientProtocolConfig[config_key::initPacketJunkSize] = "0"; + clientProtocolConfig[config_key::responsePacketJunkSize] = "0"; + clientProtocolConfig[config_key::initPacketMagicHeader] = "1"; + clientProtocolConfig[config_key::responsePacketMagicHeader] = "2"; + clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3"; + clientProtocolConfig[config_key::transportPacketMagicHeader] = "4"; - containerConfig[config_key::last_config] = QString(QJsonDocument(protocolConfig).toJson()); - container["wireguard"] = containerConfig; + clientProtocolConfig[config_key::isObfuscationEnabled] = true; + + serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson()); + container["wireguard"] = serverProtocolConfig; containers.replace(0, container); m_config[config_key::containers] = containers; } From 425acc5f8b220cf2912f25f4b0b73075dcb93bb1 Mon Sep 17 00:00:00 2001 From: albexk Date: Mon, 23 Sep 2024 17:53:56 +0300 Subject: [PATCH 11/11] Add support for obfuscated WG on Android --- client/android/awg/src/main/kotlin/Awg.kt | 17 +-- .../android/awg/src/main/kotlin/AwgConfig.kt | 108 ------------------ .../vpn/protocol/wireguard/Wireguard.kt | 17 +++ .../vpn/protocol/wireguard/WireguardConfig.kt | 73 +++++++++++- 4 files changed, 93 insertions(+), 122 deletions(-) delete mode 100644 client/android/awg/src/main/kotlin/AwgConfig.kt diff --git a/client/android/awg/src/main/kotlin/Awg.kt b/client/android/awg/src/main/kotlin/Awg.kt index fbd1cce0..c147ae03 100644 --- a/client/android/awg/src/main/kotlin/Awg.kt +++ b/client/android/awg/src/main/kotlin/Awg.kt @@ -1,28 +1,21 @@ package org.amnezia.vpn.protocol.awg import org.amnezia.vpn.protocol.wireguard.Wireguard -import org.amnezia.vpn.util.optStringOrNull +import org.amnezia.vpn.protocol.wireguard.WireguardConfig import org.json.JSONObject class Awg : Wireguard() { override val ifName: String = "awg0" - override fun parseConfig(config: JSONObject): AwgConfig { + override fun parseConfig(config: JSONObject): WireguardConfig { val configData = config.getJSONObject("awg_config_data") - return AwgConfig.build { + return WireguardConfig.build { + setUseProtocolExtension(true) + configExtensionParameters(configData) configWireguard(config, configData) configSplitTunneling(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()) } } } } diff --git a/client/android/awg/src/main/kotlin/AwgConfig.kt b/client/android/awg/src/main/kotlin/AwgConfig.kt deleted file mode 100644 index 014c6e0a..00000000 --- a/client/android/awg/src/main/kotlin/AwgConfig.kt +++ /dev/null @@ -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() - } -} diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index 31e7f9be..ac11374b 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -129,12 +129,29 @@ open class Wireguard : Protocol() { val port = configData.getInt("port") setEndpoint(InetEndpoint(host, port)) + if (configData.optBoolean("isObfuscationEnabled")) { + setUseProtocolExtension(true) + configExtensionParameters(configData) + } + configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) } configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) } configData.getString("server_pub_key").let { setPublicKeyHex(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) { if (tunnelHandle != -1) { Log.w(TAG, "Tunnel already up") diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt index 09269f54..7ae3d43b 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt @@ -1,6 +1,7 @@ package org.amnezia.vpn.protocol.wireguard import android.util.Base64 +import org.amnezia.vpn.protocol.BadConfigException import org.amnezia.vpn.protocol.ProtocolConfig import org.amnezia.vpn.util.net.InetEndpoint @@ -12,7 +13,17 @@ open class WireguardConfig protected constructor( val persistentKeepalive: Int, val publicKeyHex: 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) { protected constructor(builder: Builder) : this( @@ -21,7 +32,17 @@ open class WireguardConfig protected constructor( builder.persistentKeepalive, builder.publicKeyHex, 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()) { @@ -33,6 +54,30 @@ open class WireguardConfig protected constructor( open fun appendDeviceLine(sb: StringBuilder) = with(sb) { 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) { @@ -65,6 +110,18 @@ open class WireguardConfig protected constructor( 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 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 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) } }