diff --git a/client/platforms/ios/PacketTunnelProvider+Xray.swift b/client/platforms/ios/PacketTunnelProvider+Xray.swift index 6a08bb6a9..4d3d723ca 100644 --- a/client/platforms/ios/PacketTunnelProvider+Xray.swift +++ b/client/platforms/ios/PacketTunnelProvider+Xray.swift @@ -21,6 +21,44 @@ extension Constants { } extension PacketTunnelProvider { + private func applyXraySplitTunnel(_ xrayConfig: XrayConfig, + settings: NEPacketTunnelNetworkSettings) { + guard let splitTunnelType = xrayConfig.splitTunnelType else { + return + } + + guard let splitTunnelSites = xrayConfig.splitTunnelSites else { + xrayLog(.error, message: "Split tunnel sites are not set") + return + } + + if splitTunnelType == 1 { + var ipv4IncludedRoutes = [NEIPv4Route]() + + for allowedIPString in splitTunnelSites { + if let allowedIP = IPAddressRange(from: allowedIPString) { + ipv4IncludedRoutes.append(NEIPv4Route( + destinationAddress: "\(allowedIP.address)", + subnetMask: "\(allowedIP.subnetMask())")) + } + } + + settings.ipv4Settings?.includedRoutes = ipv4IncludedRoutes + } else if splitTunnelType == 2 { + var ipv4ExcludedRoutes = [NEIPv4Route]() + + for excludedIPString in splitTunnelSites { + if let excludedIP = IPAddressRange(from: excludedIPString) { + ipv4ExcludedRoutes.append(NEIPv4Route( + destinationAddress: "\(excludedIP.address)", + subnetMask: "\(excludedIP.subnetMask())")) + } + } + + settings.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes + } + } + func startXray(completionHandler: @escaping (Error?) -> Void) { // Xray configuration @@ -72,6 +110,7 @@ extension PacketTunnelProvider { settings.dnsSettings = !dnsArray.isEmpty ? NEDNSSettings(servers: dnsArray) : NEDNSSettings(servers: ["1.1.1.1"]) + applyXraySplitTunnel(xrayConfig, settings: settings) let xrayConfigData = xrayConfig.config.data(using: .utf8) diff --git a/client/platforms/ios/XrayConfig.swift b/client/platforms/ios/XrayConfig.swift index 9c47a2a18..9c533a93e 100644 --- a/client/platforms/ios/XrayConfig.swift +++ b/client/platforms/ios/XrayConfig.swift @@ -3,5 +3,7 @@ import Foundation struct XrayConfig: Decodable { let dns1: String? let dns2: String? + let splitTunnelType: Int? + let splitTunnelSites: [String]? let config: String } diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index 9302680bd..fc9498d02 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -684,6 +684,15 @@ bool IosController::setupXray() QJsonObject finalConfig; finalConfig.insert(config_key::dns1, m_rawConfig[config_key::dns1].toString()); finalConfig.insert(config_key::dns2, m_rawConfig[config_key::dns2].toString()); + finalConfig.insert(config_key::splitTunnelType, m_rawConfig[config_key::splitTunnelType]); + + QJsonArray splitTunnelSites = m_rawConfig[config_key::splitTunnelSites].toArray(); + + for(int index = 0; index < splitTunnelSites.count(); index++) { + splitTunnelSites[index] = splitTunnelSites[index].toString().remove(" "); + } + + finalConfig.insert(config_key::splitTunnelSites, splitTunnelSites); finalConfig.insert(config_key::config, xrayConfigStr); QJsonDocument finalConfigDoc(finalConfig);