mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc4573ce75 | |||
| ab6f96bb00 | |||
| 23a8dad37f | |||
| b5c121258a | |||
| 2c45c46a45 | |||
| 70daf4c236 | |||
| 1ece6fe418 | |||
| b075676be6 |
@@ -1,81 +1,28 @@
|
|||||||
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.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "protocol": "awg",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "awg_config_data": {
|
|
||||||
* "H1": "969537490",
|
|
||||||
* "H2": "481688153",
|
|
||||||
* "H3": "2049399200",
|
|
||||||
* "H4": "52029755",
|
|
||||||
* "Jc": "3",
|
|
||||||
* "Jmax": "1000",
|
|
||||||
* "Jmin": "50",
|
|
||||||
* "S1": "49",
|
|
||||||
* "S2": "60",
|
|
||||||
* "client_ip": "10.8.1.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "port": 12345,
|
|
||||||
* "client_pub_key": "clientPublicKeyBase64",
|
|
||||||
* "client_priv_key": "privateKeyBase64",
|
|
||||||
* "psk_key": "presharedKeyBase64",
|
|
||||||
* "server_pub_key": "publicKeyBase64",
|
|
||||||
* "config": "[Interface]
|
|
||||||
* Address = 10.8.1.1/32
|
|
||||||
* DNS = 1.1.1.1, 1.0.0.1
|
|
||||||
* PrivateKey = privateKeyBase64
|
|
||||||
* Jc = 3
|
|
||||||
* Jmin = 50
|
|
||||||
* Jmax = 1000
|
|
||||||
* S1 = 49
|
|
||||||
* S2 = 60
|
|
||||||
* H1 = 969537490
|
|
||||||
* H2 = 481688153
|
|
||||||
* H3 = 2049399200
|
|
||||||
* H4 = 52029755
|
|
||||||
*
|
|
||||||
* [Peer]
|
|
||||||
* PublicKey = publicKeyBase64
|
|
||||||
* PresharedKey = presharedKeyBase64
|
|
||||||
* AllowedIPs = 0.0.0.0/0, ::/0
|
|
||||||
* Endpoint = 100.100.100.0:12345
|
|
||||||
* PersistentKeepalive = 25
|
|
||||||
* "
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
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): AwgConfig {
|
||||||
val configDataJson = config.getJSONObject("awg_config_data")
|
val configData = config.getJSONObject("awg_config_data")
|
||||||
val configData = parseConfigData(configDataJson.getString("config"))
|
|
||||||
return AwgConfig.build {
|
return AwgConfig.build {
|
||||||
configWireguard(configData, configDataJson)
|
configWireguard(config, configData)
|
||||||
configSplitTunneling(config)
|
configSplitTunneling(config)
|
||||||
configAppSplitTunneling(config)
|
configAppSplitTunneling(config)
|
||||||
configData["Jc"]?.let { setJc(it.toInt()) }
|
configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
|
||||||
configData["Jmin"]?.let { setJmin(it.toInt()) }
|
configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
|
||||||
configData["Jmax"]?.let { setJmax(it.toInt()) }
|
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
||||||
configData["S1"]?.let { setS1(it.toInt()) }
|
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
||||||
configData["S2"]?.let { setS2(it.toInt()) }
|
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
||||||
configData["H1"]?.let { setH1(it.toLong()) }
|
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
||||||
configData["H2"]?.let { setH2(it.toLong()) }
|
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
||||||
configData["H3"]?.let { setH3(it.toLong()) }
|
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
||||||
configData["H4"]?.let { setH4(it.toLong()) }
|
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,36 +5,6 @@ import net.openvpn.ovpn3.ClientAPI_Config
|
|||||||
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config Example:
|
|
||||||
* {
|
|
||||||
* "protocol": "cloak",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "openvpn_config_data": {
|
|
||||||
* "config": "openVpnConfig"
|
|
||||||
* }
|
|
||||||
* "cloak_config_data": {
|
|
||||||
* "BrowserSig": "chrome",
|
|
||||||
* "EncryptionMethod": "aes-gcm",
|
|
||||||
* "NumConn": 1,
|
|
||||||
* "ProxyMethod": "openvpn",
|
|
||||||
* "PublicKey": "PublicKey=",
|
|
||||||
* "RemoteHost": "100.100.100.0",
|
|
||||||
* "RemotePort": "443",
|
|
||||||
* "ServerName": "servername",
|
|
||||||
* "StreamTimeout": 300,
|
|
||||||
* "Transport": "direct",
|
|
||||||
* "UID": "UID="
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Cloak : OpenVpn() {
|
class Cloak : OpenVpn() {
|
||||||
|
|
||||||
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
||||||
|
|||||||
@@ -16,23 +16,6 @@ import org.amnezia.vpn.util.net.getLocalNetworks
|
|||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config Example:
|
|
||||||
* {
|
|
||||||
* "protocol": "openvpn",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "openvpn_config_data": {
|
|
||||||
* "config": "openVpnConfig"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
open class OpenVpn : Protocol() {
|
open class OpenVpn : Protocol() {
|
||||||
|
|
||||||
private var openVpnClient: OpenVpnClient? = null
|
private var openVpnClient: OpenVpnClient? = null
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.amnezia.vpn.util
|
||||||
|
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
inline fun <reified T> JSONArray.asSequence(): Sequence<T> =
|
||||||
|
(0..<length()).asSequence().map { get(it) as T }
|
||||||
|
|
||||||
|
fun JSONObject.optStringOrNull(name: String) = optString(name).ifEmpty { null }
|
||||||
+24
-69
@@ -1,7 +1,6 @@
|
|||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.net.VpnService.Builder
|
import android.net.VpnService.Builder
|
||||||
import java.util.TreeMap
|
|
||||||
import org.amnezia.awg.GoBackend
|
import org.amnezia.awg.GoBackend
|
||||||
import org.amnezia.vpn.protocol.Protocol
|
import org.amnezia.vpn.protocol.Protocol
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
@@ -9,46 +8,13 @@ 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.Log
|
import org.amnezia.vpn.util.Log
|
||||||
|
import org.amnezia.vpn.util.asSequence
|
||||||
import org.amnezia.vpn.util.net.InetEndpoint
|
import org.amnezia.vpn.util.net.InetEndpoint
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
|
import org.amnezia.vpn.util.optStringOrNull
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "protocol": "wireguard",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "wireguard_config_data": {
|
|
||||||
* "client_ip": "10.8.1.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "port": 12345,
|
|
||||||
* "client_pub_key": "clientPublicKeyBase64",
|
|
||||||
* "client_priv_key": "privateKeyBase64",
|
|
||||||
* "psk_key": "presharedKeyBase64",
|
|
||||||
* "server_pub_key": "publicKeyBase64",
|
|
||||||
* "config": "[Interface]
|
|
||||||
* Address = 10.8.1.1/32
|
|
||||||
* DNS = 1.1.1.1, 1.0.0.1
|
|
||||||
* PrivateKey = privateKeyBase64
|
|
||||||
*
|
|
||||||
* [Peer]
|
|
||||||
* PublicKey = publicKeyBase64
|
|
||||||
* PresharedKey = presharedKeyBase64
|
|
||||||
* AllowedIPs = 0.0.0.0/0, ::/0
|
|
||||||
* Endpoint = 100.100.100.0:12345
|
|
||||||
* PersistentKeepalive = 25
|
|
||||||
* "
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
private const val TAG = "Wireguard"
|
private const val TAG = "Wireguard"
|
||||||
|
|
||||||
open class Wireguard : Protocol() {
|
open class Wireguard : Protocol() {
|
||||||
@@ -86,60 +52,49 @@ open class Wireguard : Protocol() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configDataJson = config.getJSONObject("wireguard_config_data")
|
val configData = config.getJSONObject("wireguard_config_data")
|
||||||
val configData = parseConfigData(configDataJson.getString("config"))
|
|
||||||
return WireguardConfig.build {
|
return WireguardConfig.build {
|
||||||
configWireguard(configData, configDataJson)
|
configWireguard(config, configData)
|
||||||
configSplitTunneling(config)
|
configSplitTunneling(config)
|
||||||
configAppSplitTunneling(config)
|
configAppSplitTunneling(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun WireguardConfig.Builder.configWireguard(configData: Map<String, String>, configDataJson: JSONObject) {
|
protected fun WireguardConfig.Builder.configWireguard(config: JSONObject, configData: JSONObject) {
|
||||||
configData["Address"]?.split(",")?.map { address ->
|
configData.getString("client_ip").split(",").map { address ->
|
||||||
InetNetwork.parse(address.trim())
|
InetNetwork.parse(address.trim())
|
||||||
}?.forEach(::addAddress)
|
}.forEach(::addAddress)
|
||||||
|
|
||||||
configData["DNS"]?.split(",")?.map { dns ->
|
config.optStringOrNull("dns1")?.let { dns ->
|
||||||
parseInetAddress(dns.trim())
|
addDnsServer(parseInetAddress(dns.trim()))
|
||||||
}?.forEach(::addDnsServer)
|
}
|
||||||
|
|
||||||
|
config.optStringOrNull("dns2")?.let { dns ->
|
||||||
|
addDnsServer(parseInetAddress(dns.trim()))
|
||||||
|
}
|
||||||
|
|
||||||
val defRoutes = hashSetOf(
|
val defRoutes = hashSetOf(
|
||||||
InetNetwork("0.0.0.0", 0),
|
InetNetwork("0.0.0.0", 0),
|
||||||
InetNetwork("::", 0)
|
InetNetwork("::", 0)
|
||||||
)
|
)
|
||||||
val routes = hashSetOf<InetNetwork>()
|
val routes = hashSetOf<InetNetwork>()
|
||||||
configData["AllowedIPs"]?.split(",")?.map { route ->
|
configData.getJSONArray("allowed_ips").asSequence<String>().map { route ->
|
||||||
InetNetwork.parse(route.trim())
|
InetNetwork.parse(route.trim())
|
||||||
}?.forEach(routes::add)
|
}.forEach(routes::add)
|
||||||
// if the allowed IPs list contains at least one non-default route, disable global split tunneling
|
// if the allowed IPs list contains at least one non-default route, disable global split tunneling
|
||||||
if (routes.any { it !in defRoutes }) disableSplitTunneling()
|
if (routes.any { it !in defRoutes }) disableSplitTunneling()
|
||||||
addRoutes(routes)
|
addRoutes(routes)
|
||||||
|
|
||||||
configDataJson.optString("mtu").let { mtu ->
|
configData.optStringOrNull("mtu")?.let { setMtu(it.toInt()) }
|
||||||
if (mtu.isNotEmpty()) {
|
|
||||||
setMtu(mtu.toInt())
|
|
||||||
} else {
|
|
||||||
configData["MTU"]?.let { setMtu(it.toInt()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) }
|
val host = configData.getString("hostName").let { parseInetAddress(it.trim()) }
|
||||||
configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) }
|
val port = configData.getInt("port")
|
||||||
configData["PrivateKey"]?.let { setPrivateKeyHex(it.base64ToHex()) }
|
setEndpoint(InetEndpoint(host, port))
|
||||||
configData["PublicKey"]?.let { setPublicKeyHex(it.base64ToHex()) }
|
|
||||||
configData["PresharedKey"]?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun parseConfigData(data: String): Map<String, String> {
|
configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
|
||||||
val parsedData = TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER)
|
configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
|
||||||
data.lineSequence()
|
configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
|
||||||
.filter { it.isNotEmpty() && !it.startsWith('[') }
|
configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
||||||
.forEach { line ->
|
|
||||||
val attr = line.split("=", limit = 2)
|
|
||||||
parsedData[attr.first().trim()] = attr.last().trim()
|
|
||||||
}
|
|
||||||
return parsedData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
|
|||||||
@@ -20,69 +20,6 @@ import org.amnezia.vpn.util.net.InetNetwork
|
|||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "appSplitTunnelType": 0,
|
|
||||||
* "config_version": 0,
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "protocol": "xray",
|
|
||||||
* "splitTunnelApps": [],
|
|
||||||
* "splitTunnelSites": [],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "xray_config_data": {
|
|
||||||
* "inbounds": [
|
|
||||||
* {
|
|
||||||
* "listen": "127.0.0.1",
|
|
||||||
* "port": 8080,
|
|
||||||
* "protocol": "socks",
|
|
||||||
* "settings": {
|
|
||||||
* "udp": true
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ],
|
|
||||||
* "log": {
|
|
||||||
* "loglevel": "error"
|
|
||||||
* },
|
|
||||||
* "outbounds": [
|
|
||||||
* {
|
|
||||||
* "protocol": "vless",
|
|
||||||
* "settings": {
|
|
||||||
* "vnext": [
|
|
||||||
* {
|
|
||||||
* "address": "100.100.100.0",
|
|
||||||
* "port": 443,
|
|
||||||
* "users": [
|
|
||||||
* {
|
|
||||||
* "encryption": "none",
|
|
||||||
* "flow": "xtls-rprx-vision",
|
|
||||||
* "id": "id"
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* },
|
|
||||||
* "streamSettings": {
|
|
||||||
* "network": "tcp",
|
|
||||||
* "realitySettings": {
|
|
||||||
* "fingerprint": "chrome",
|
|
||||||
* "publicKey": "publicKey",
|
|
||||||
* "serverName": "google.com",
|
|
||||||
* "shortId": "id",
|
|
||||||
* "spiderX": ""
|
|
||||||
* },
|
|
||||||
* "security": "reality"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
private const val TAG = "Xray"
|
private const val TAG = "Xray"
|
||||||
private const val LIBXRAY_TAG = "libXray"
|
private const val LIBXRAY_TAG = "libXray"
|
||||||
|
|
||||||
|
|||||||
@@ -187,6 +187,10 @@ 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;
|
||||||
|
QJsonArray allowedIps { "0.0.0.0/0" };
|
||||||
|
jConfig[config_key::allowed_ips] = allowedIps;
|
||||||
|
|
||||||
jConfig[config_key::clientId] = connData.clientPubKey;
|
jConfig[config_key::clientId] = connData.clientPubKey;
|
||||||
|
|
||||||
return QJsonDocument(jConfig).toJson();
|
return QJsonDocument(jConfig).toJson();
|
||||||
|
|||||||
@@ -149,9 +149,13 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
QJsonArray jsAllowedIPAddesses;
|
QJsonArray jsAllowedIPAddesses;
|
||||||
|
|
||||||
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
|
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
|
||||||
QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(","));
|
|
||||||
|
|
||||||
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
|
bool allowSplitTunnelFromAppSettings = false;
|
||||||
|
if (!plainAllowedIP.isEmpty() && plainAllowedIP.contains("0.0.0.0/0")) {
|
||||||
|
allowSplitTunnelFromAppSettings = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allowSplitTunnelFromAppSettings) {
|
||||||
// Use AllowedIP list from WG config because of higher priority
|
// Use AllowedIP list from WG config because of higher priority
|
||||||
for (auto v : plainAllowedIP) {
|
for (auto v : plainAllowedIP) {
|
||||||
QString ipRange = v.toString();
|
QString ipRange = v.toString();
|
||||||
@@ -170,7 +174,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Use APP split tunnel
|
// Use APP split tunnel
|
||||||
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
||||||
QJsonObject range_ipv4;
|
QJsonObject range_ipv4;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ extension PacketTunnelProvider {
|
|||||||
|
|
||||||
if tunnelConfiguration.peers.first!.allowedIPs
|
if tunnelConfiguration.peers.first!.allowedIPs
|
||||||
.map({ $0.stringRepresentation })
|
.map({ $0.stringRepresentation })
|
||||||
.joined(separator: ", ") == "0.0.0.0/0, ::/0" {
|
.contains("0.0.0.0/0") {
|
||||||
if wgConfig.splitTunnelType == 1 {
|
if wgConfig.splitTunnelType == 1 {
|
||||||
for index in tunnelConfiguration.peers.indices {
|
for index in tunnelConfiguration.peers.indices {
|
||||||
tunnelConfiguration.peers[index].allowedIPs.removeAll()
|
tunnelConfiguration.peers[index].allowedIPs.removeAll()
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ bool IosController::setupWireGuard()
|
|||||||
if (config.contains(config_key::allowed_ips) && config[config_key::allowed_ips].isArray()) {
|
if (config.contains(config_key::allowed_ips) && config[config_key::allowed_ips].isArray()) {
|
||||||
wgConfig.insert(config_key::allowed_ips, config[config_key::allowed_ips]);
|
wgConfig.insert(config_key::allowed_ips, config[config_key::allowed_ips]);
|
||||||
} else {
|
} else {
|
||||||
QJsonArray allowed_ips { "0.0.0.0/0", "::/0" };
|
QJsonArray allowed_ips { "0.0.0.0/0" };
|
||||||
wgConfig.insert(config_key::allowed_ips, allowed_ips);
|
wgConfig.insert(config_key::allowed_ips, allowed_ips);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,7 +576,7 @@ bool IosController::setupAwg()
|
|||||||
if (config.contains(config_key::allowed_ips) && config[config_key::allowed_ips].isArray()) {
|
if (config.contains(config_key::allowed_ips) && config[config_key::allowed_ips].isArray()) {
|
||||||
wgConfig.insert(config_key::allowed_ips, config[config_key::allowed_ips]);
|
wgConfig.insert(config_key::allowed_ips, config[config_key::allowed_ips]);
|
||||||
} else {
|
} else {
|
||||||
QJsonArray allowed_ips { "0.0.0.0/0", "::/0" };
|
QJsonArray allowed_ips { "0.0.0.0/0" };
|
||||||
wgConfig.insert(config_key::allowed_ips, allowed_ips);
|
wgConfig.insert(config_key::allowed_ips, allowed_ips);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ H4 = $TRANSPORT_PACKET_MAGIC_HEADER
|
|||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY
|
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY
|
||||||
PresharedKey = $WIREGUARD_PSK
|
PresharedKey = $WIREGUARD_PSK
|
||||||
AllowedIPs = 0.0.0.0/0, ::/0
|
AllowedIPs = 0.0.0.0/0
|
||||||
Endpoint = $SERVER_IP_ADDRESS:$AWG_SERVER_PORT
|
Endpoint = $SERVER_IP_ADDRESS:$AWG_SERVER_PORT
|
||||||
PersistentKeepalive = 25
|
PersistentKeepalive = 25
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ PrivateKey = $WIREGUARD_CLIENT_PRIVATE_KEY
|
|||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY
|
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY
|
||||||
PresharedKey = $WIREGUARD_PSK
|
PresharedKey = $WIREGUARD_PSK
|
||||||
AllowedIPs = 0.0.0.0/0, ::/0
|
AllowedIPs = 0.0.0.0/0
|
||||||
Endpoint = $SERVER_IP_ADDRESS:$WIREGUARD_SERVER_PORT
|
Endpoint = $SERVER_IP_ADDRESS:$WIREGUARD_SERVER_PORT
|
||||||
PersistentKeepalive = 25
|
PersistentKeepalive = 25
|
||||||
|
|||||||
@@ -395,7 +395,11 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
|||||||
lastConfig[config_key::mtu] = configMap.value("MTU");
|
lastConfig[config_key::mtu] = configMap.value("MTU");
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(","));
|
if (!configMap.value("PersistentKeepalive").isEmpty()) {
|
||||||
|
lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive");
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
|
||||||
|
|
||||||
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
||||||
|
|
||||||
|
|||||||
@@ -694,7 +694,16 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
|
|||||||
QJsonObject serverProtocolConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
|
QJsonObject serverProtocolConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
|
||||||
QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString();
|
QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString();
|
||||||
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(clientProtocolConfigString.toUtf8()).object();
|
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(clientProtocolConfigString.toUtf8()).object();
|
||||||
return (clientProtocolConfigString.contains("AllowedIPs") && !clientProtocolConfigString.contains("AllowedIPs = 0.0.0.0/0, ::/0"))
|
QString nativeProtocolConfigString = clientProtocolConfig.value(config_key::config).toString();
|
||||||
|
|
||||||
|
const static QRegularExpression allowedIpsRegExp("AllowedIPs\\s*=\\s*([^\n]*)");
|
||||||
|
QRegularExpressionMatch allowedIpsMatch = allowedIpsRegExp.match(nativeProtocolConfigString);
|
||||||
|
QString allowedIpsString;
|
||||||
|
if (allowedIpsMatch.hasCaptured(1)) {
|
||||||
|
allowedIpsString = allowedIpsMatch.captured(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !allowedIpsString.contains("0.0.0.0/0")
|
||||||
|| (!clientProtocolConfig.value(config_key::allowed_ips).toArray().isEmpty()
|
|| (!clientProtocolConfig.value(config_key::allowed_ips).toArray().isEmpty()
|
||||||
&& !clientProtocolConfig.value(config_key::allowed_ips).toArray().contains("0.0.0.0/0"));
|
&& !clientProtocolConfig.value(config_key::allowed_ips).toArray().contains("0.0.0.0/0"));
|
||||||
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
|
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import "../Config"
|
|||||||
DrawerType2 {
|
DrawerType2 {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
property bool isAppSplitTunnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
expandedHeight: parent.height * 0.9
|
expandedHeight: parent.height * 0.9
|
||||||
@@ -24,6 +24,8 @@ DrawerType2 {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
property bool isServerSplitTunnelingEnabled: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root
|
target: root
|
||||||
enabled: !GC.isMobile()
|
enabled: !GC.isMobile()
|
||||||
@@ -53,7 +55,7 @@ DrawerType2 {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
|
||||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
visible: isServerSplitTunnelingEnabled
|
||||||
|
|
||||||
text: qsTr("Split tunneling on the server")
|
text: qsTr("Split tunneling on the server")
|
||||||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||||
@@ -68,7 +70,7 @@ DrawerType2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
visible: isServerSplitTunnelingEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
@@ -95,7 +97,7 @@ DrawerType2 {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: appSplitTunnelingSwitch
|
id: appSplitTunnelingSwitch
|
||||||
visible: isAppSplitTinnelingEnabled
|
visible: isAppSplitTunnelingEnabled
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ DrawerType2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: isAppSplitTinnelingEnabled
|
visible: isAppSplitTunnelingEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-32
@@ -291,43 +291,68 @@ void VpnConnection::appendKillSwitchConfig()
|
|||||||
|
|
||||||
void VpnConnection::appendSplitTunnelingConfig()
|
void VpnConnection::appendSplitTunnelingConfig()
|
||||||
{
|
{
|
||||||
if (m_vpnConfiguration.value(config_key::configVersion).toInt()) {
|
// this block is for old native configs and for old self-hosted configs
|
||||||
auto protocolName = m_vpnConfiguration.value(config_key::vpnproto).toString();
|
auto protocolName = m_vpnConfiguration.value(config_key::vpnproto).toString();
|
||||||
if (protocolName == ProtocolProps::protoToString(Proto::Awg)) {
|
if (protocolName == ProtocolProps::protoToString(Proto::Awg) || protocolName == ProtocolProps::protoToString(Proto::WireGuard)) {
|
||||||
auto configData = m_vpnConfiguration.value(protocolName + "_config_data").toObject();
|
auto configData = m_vpnConfiguration.value(protocolName + "_config_data").toObject();
|
||||||
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configData.value("allowed_ips").toString().split(","));
|
if (configData.value(config_key::allowed_ips).isString()) {
|
||||||
QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(","));
|
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configData.value(config_key::allowed_ips).toString().split(", "));
|
||||||
|
configData.insert(config_key::allowed_ips, allowedIpsJsonArray);
|
||||||
if (allowedIpsJsonArray != defaultAllowedIP) {
|
m_vpnConfiguration.insert(protocolName + "_config_data", configData);
|
||||||
allowedIpsJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString());
|
} else if (configData.value(config_key::allowed_ips).isUndefined()) {
|
||||||
allowedIpsJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString());
|
auto nativeConfig = configData.value(config_key::config).toString();
|
||||||
|
auto nativeConfigLines = nativeConfig.split("\n");
|
||||||
m_vpnConfiguration.insert(config_key::splitTunnelType, Settings::RouteMode::VpnOnlyForwardSites);
|
for (auto &line : nativeConfigLines) {
|
||||||
m_vpnConfiguration.insert(config_key::splitTunnelSites, allowedIpsJsonArray);
|
if (line.contains("AllowedIPs")) {
|
||||||
}
|
auto allowedIpsString = line.split(" = ");
|
||||||
}
|
if (allowedIpsString.size() < 1) {
|
||||||
} else {
|
break;
|
||||||
Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites;
|
}
|
||||||
QJsonArray sitesJsonArray;
|
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(allowedIpsString.at(1).split(", "));
|
||||||
if (m_settings->isSitesSplitTunnelingEnabled()) {
|
configData.insert(config_key::allowed_ips, allowedIpsJsonArray);
|
||||||
routeMode = m_settings->routeMode();
|
m_vpnConfiguration.insert(protocolName + "_config_data", configData);
|
||||||
|
break;
|
||||||
auto sites = m_settings->getVpnIps(routeMode);
|
}
|
||||||
for (const auto &site : sites) {
|
|
||||||
sitesJsonArray.append(site);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow traffic to Amnezia DNS
|
|
||||||
if (routeMode == Settings::VpnOnlyForwardSites) {
|
|
||||||
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString());
|
|
||||||
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode);
|
if (configData.value(config_key::persistent_keep_alive).isUndefined()) {
|
||||||
m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray);
|
auto nativeConfig = configData.value(config_key::config).toString();
|
||||||
|
auto nativeConfigLines = nativeConfig.split("\n");
|
||||||
|
for (auto &line : nativeConfigLines) {
|
||||||
|
if (line.contains("PersistentKeepalive")) {
|
||||||
|
auto persistentKeepaliveString = line.split(" = ");
|
||||||
|
if (persistentKeepaliveString.size() < 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
configData.insert(config_key::persistent_keep_alive, persistentKeepaliveString.at(1));
|
||||||
|
m_vpnConfiguration.insert(protocolName + "_config_data", configData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites;
|
||||||
|
QJsonArray sitesJsonArray;
|
||||||
|
if (m_settings->isSitesSplitTunnelingEnabled()) {
|
||||||
|
routeMode = m_settings->routeMode();
|
||||||
|
|
||||||
|
auto sites = m_settings->getVpnIps(routeMode);
|
||||||
|
for (const auto &site : sites) {
|
||||||
|
sitesJsonArray.append(site);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow traffic to Amnezia DNS
|
||||||
|
if (routeMode == Settings::VpnOnlyForwardSites) {
|
||||||
|
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString());
|
||||||
|
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode);
|
||||||
|
m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray);
|
||||||
|
|
||||||
Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps;
|
Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps;
|
||||||
QJsonArray appsJsonArray;
|
QJsonArray appsJsonArray;
|
||||||
if (m_settings->isAppsSplitTunnelingEnabled()) {
|
if (m_settings->isAppsSplitTunnelingEnabled()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user