Compare commits

...

8 Commits

16 changed files with 139 additions and 291 deletions
+12 -65
View File
@@ -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 }
@@ -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();
+6 -3
View File
@@ -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()
+2 -2
View File
@@ -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);
} }
+1 -1
View File
@@ -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
+5 -1
View File
@@ -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;
+10 -1
View File
@@ -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
View File
@@ -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()) {