diff --git a/client/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift b/client/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift index b7aaf3d8..a648281a 100644 --- a/client/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift +++ b/client/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift @@ -18,40 +18,32 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate { // send empty string to NEDNSSettings.matchDomains networkSettings?.dnsSettings?.matchDomains = [""] - if splitTunnelType == "1" { + if splitTunnelType == 1 { var ipv4IncludedRoutes = [NEIPv4Route]() - let STSdata = Data(splitTunnelSites!.utf8) - do { - guard let STSArray = try JSONSerialization.jsonObject(with: STSdata) as? [String] else { return } - for allowedIPString in STSArray { - if let allowedIP = IPAddressRange(from: allowedIPString) { - ipv4IncludedRoutes.append(NEIPv4Route( - destinationAddress: "\(allowedIP.address)", - subnetMask: "\(allowedIP.subnetMask())")) - } + + for allowedIPString in splitTunnelSites { + if let allowedIP = IPAddressRange(from: allowedIPString) { + ipv4IncludedRoutes.append(NEIPv4Route( + destinationAddress: "\(allowedIP.address)", + subnetMask: "\(allowedIP.subnetMask())")) } - } catch { - wg_log(.error, message: "Parse JSONSerialization Error") } + networkSettings?.ipv4Settings?.includedRoutes = ipv4IncludedRoutes } else { - if splitTunnelType == "2" { + if splitTunnelType == 2 { var ipv4ExcludedRoutes = [NEIPv4Route]() var ipv4IncludedRoutes = [NEIPv4Route]() var ipv6IncludedRoutes = [NEIPv6Route]() - let STSdata = Data(splitTunnelSites!.utf8) - do { - guard let STSArray = try JSONSerialization.jsonObject(with: STSdata) as? [String] else { return } - for excludeIPString in STSArray { - if let excludeIP = IPAddressRange(from: excludeIPString) { - ipv4ExcludedRoutes.append(NEIPv4Route( - destinationAddress: "\(excludeIP.address)", - subnetMask: "\(excludeIP.subnetMask())")) - } + + for excludeIPString in splitTunnelSites { + if let excludeIP = IPAddressRange(from: excludeIPString) { + ipv4ExcludedRoutes.append(NEIPv4Route( + destinationAddress: "\(excludeIP.address)", + subnetMask: "\(excludeIP.subnetMask())")) } - } catch { - wg_log(.error, message: "Parse JSONSerialization Error") } + if let allIPv4 = IPAddressRange(from: "0.0.0.0/0") { ipv4IncludedRoutes.append(NEIPv4Route( destinationAddress: "\(allIPv4.address)", diff --git a/client/platforms/ios/PacketTunnelProvider.swift b/client/platforms/ios/PacketTunnelProvider.swift index dc0403e3..e48d95d2 100644 --- a/client/platforms/ios/PacketTunnelProvider.swift +++ b/client/platforms/ios/PacketTunnelProvider.swift @@ -50,8 +50,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider { private let dispatchQueue = DispatchQueue(label: "PacketTunnel", qos: .utility) private var openVPNConfig: Data? - var splitTunnelType: String? - var splitTunnelSites: String? + var splitTunnelType: Int! + var splitTunnelSites: [String]! let vpnReachability = OpenVPNReachability() @@ -81,22 +81,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider { if action == Constants.kActionStatus { handleStatusAppMessage(messageData, completionHandler: completionHandler) } - - if action == Constants.kActionStart { - splitTunnelType = message[Constants.kMessageKeySplitTunnelType] as? String - splitTunnelSites = message[Constants.kMessageKeySplitTunnelSites] as? String - } - - let callbackWrapper: (NSNumber?) -> Void = { errorCode in - // let tunnelId = self.tunnelConfig?.id ?? "" - let response: [String: Any] = [ - Constants.kMessageKeyAction: action, - Constants.kMessageKeyErrorCode: errorCode ?? NSNull(), - Constants.kMessageKeyTunnelId: 0 - ] - - completionHandler(try? JSONSerialization.data(withJSONObject: response, options: [])) - } } override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { @@ -169,110 +153,118 @@ class PacketTunnelProvider: NEPacketTunnelProvider { completionHandler: @escaping (Error?) -> Void) { guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol, let providerConfiguration = protocolConfiguration.providerConfiguration, - let wgConfig: Data = providerConfiguration[Constants.wireGuardConfigKey] as? Data else { + let wgConfigData: Data = providerConfiguration[Constants.wireGuardConfigKey] as? Data else { wg_log(.error, message: "Can't start WireGuard config missing") completionHandler(nil) return } - guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).str, - let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) - else { - wg_log(.error, message: "Can't parse WireGuard config") - completionHandler(nil) - return - } + do { + let wgConfig = try JSONDecoder().decode(WGConfig.self, from: wgConfigData) + let wgConfigStr = wgConfig.str + log(.info, message: "wgConfig: \(wgConfig.redux.replacingOccurrences(of: "\n", with: " "))") - log(.info, message: "wgConfig: \(wgConfigStr.replacingOccurrences(of: "\n", with: " "))") + let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: wgConfigStr) - if tunnelConfiguration.peers.first!.allowedIPs - .map({ $0.stringRepresentation }) - .joined(separator: ", ") == "0.0.0.0/0, ::/0" { - if splitTunnelType == "1" { - for index in tunnelConfiguration.peers.indices { - tunnelConfiguration.peers[index].allowedIPs.removeAll() - var allowedIPs = [IPAddressRange]() - let STSdata = Data(splitTunnelSites!.utf8) - do { - guard let STSArray = try JSONSerialization.jsonObject(with: STSdata) as? [String] else { return } - for allowedIPString in STSArray { + if tunnelConfiguration.peers.first!.allowedIPs + .map({ $0.stringRepresentation }) + .joined(separator: ", ") == "0.0.0.0/0, ::/0" { + if wgConfig.splitTunnelType == 1 { + for index in tunnelConfiguration.peers.indices { + tunnelConfiguration.peers[index].allowedIPs.removeAll() + var allowedIPs = [IPAddressRange]() + + for allowedIPString in wgConfig.splitTunnelSites { if let allowedIP = IPAddressRange(from: allowedIPString) { allowedIPs.append(allowedIP) } } - } catch { - wg_log(.error, message: "Parse JSONSerialization Error") + + tunnelConfiguration.peers[index].allowedIPs = allowedIPs } - tunnelConfiguration.peers[index].allowedIPs = allowedIPs - } - } else if splitTunnelType == "2" { - for index in tunnelConfiguration.peers.indices { - var excludeIPs = [IPAddressRange]() - let STSdata = Data(splitTunnelSites!.utf8) - do { - guard let STSArray = try JSONSerialization.jsonObject(with: STSdata) as? [String] else { return } - for excludeIPString in STSArray { + } else if wgConfig.splitTunnelType == 2 { + for index in tunnelConfiguration.peers.indices { + var excludeIPs = [IPAddressRange]() + + for excludeIPString in wgConfig.splitTunnelSites { if let excludeIP = IPAddressRange(from: excludeIPString) { excludeIPs.append(excludeIP) } } - } catch { - wg_log(.error, message: "Parse JSONSerialization Error") + + tunnelConfiguration.peers[index].excludeIPs = excludeIPs } - tunnelConfiguration.peers[index].excludeIPs = excludeIPs } } - } - wg_log(.info, message: "Starting wireguard tunnel from the " + - (activationAttemptId == nil ? "OS directly, rather than the app" : "app")) + wg_log(.info, message: "Starting wireguard tunnel from the " + + (activationAttemptId == nil ? "OS directly, rather than the app" : "app")) - // Start the tunnel - wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in - guard let adapterError else { - let interfaceName = self.wgAdapter.interfaceName ?? "unknown" - wg_log(.info, message: "Tunnel interface is \(interfaceName)") - completionHandler(nil) - return - } - - switch adapterError { - case .cannotLocateTunnelFileDescriptor: - wg_log(.error, staticMessage: "Starting tunnel failed: could not determine file descriptor") - errorNotifier.notify(PacketTunnelProviderError.couldNotDetermineFileDescriptor) - completionHandler(PacketTunnelProviderError.couldNotDetermineFileDescriptor) - case .dnsResolution(let dnsErrors): - let hostnamesWithDnsResolutionFailure = dnsErrors.map { $0.address } - .joined(separator: ", ") - wg_log(.error, message: - "DNS resolution failed for the following hostnames: \(hostnamesWithDnsResolutionFailure)") - errorNotifier.notify(PacketTunnelProviderError.dnsResolutionFailure) - completionHandler(PacketTunnelProviderError.dnsResolutionFailure) - case .setNetworkSettings(let error): - wg_log(.error, message: - "Starting tunnel failed with setTunnelNetworkSettings returning \(error.localizedDescription)") - errorNotifier.notify(PacketTunnelProviderError.couldNotSetNetworkSettings) - completionHandler(PacketTunnelProviderError.couldNotSetNetworkSettings) - case .startWireGuardBackend(let errorCode): - wg_log(.error, message: "Starting tunnel failed with wgTurnOn returning \(errorCode)") - errorNotifier.notify(PacketTunnelProviderError.couldNotStartBackend) - completionHandler(PacketTunnelProviderError.couldNotStartBackend) - case .invalidState: - fatalError() + // Start the tunnel + wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in + guard let adapterError else { + let interfaceName = self.wgAdapter.interfaceName ?? "unknown" + wg_log(.info, message: "Tunnel interface is \(interfaceName)") + completionHandler(nil) + return + } + + switch adapterError { + case .cannotLocateTunnelFileDescriptor: + wg_log(.error, staticMessage: "Starting tunnel failed: could not determine file descriptor") + errorNotifier.notify(PacketTunnelProviderError.couldNotDetermineFileDescriptor) + completionHandler(PacketTunnelProviderError.couldNotDetermineFileDescriptor) + case .dnsResolution(let dnsErrors): + let hostnamesWithDnsResolutionFailure = dnsErrors.map { $0.address } + .joined(separator: ", ") + wg_log(.error, message: + "DNS resolution failed for the following hostnames: \(hostnamesWithDnsResolutionFailure)") + errorNotifier.notify(PacketTunnelProviderError.dnsResolutionFailure) + completionHandler(PacketTunnelProviderError.dnsResolutionFailure) + case .setNetworkSettings(let error): + wg_log(.error, message: + "Starting tunnel failed with setTunnelNetworkSettings returning \(error.localizedDescription)") + errorNotifier.notify(PacketTunnelProviderError.couldNotSetNetworkSettings) + completionHandler(PacketTunnelProviderError.couldNotSetNetworkSettings) + case .startWireGuardBackend(let errorCode): + wg_log(.error, message: "Starting tunnel failed with wgTurnOn returning \(errorCode)") + errorNotifier.notify(PacketTunnelProviderError.couldNotStartBackend) + completionHandler(PacketTunnelProviderError.couldNotStartBackend) + case .invalidState: + fatalError() + } } + } catch { + log(.error, message: "Can't parse WG config: \(error.localizedDescription)") + completionHandler(nil) + return } } private func startOpenVPN(completionHandler: @escaping (Error?) -> Void) { guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol, let providerConfiguration = protocolConfiguration.providerConfiguration, - let ovpnConfiguration: Data = providerConfiguration[Constants.ovpnConfigKey] as? Data else { - + let openVPNConfigData = providerConfiguration[Constants.ovpnConfigKey] as? Data else { wg_log(.error, message: "Can't start startOpenVPN()") return } - setupAndlaunchOpenVPN(withConfig: ovpnConfiguration, completionHandler: completionHandler) + do { + log(.info, message: "providerConfiguration: \(String(decoding: openVPNConfigData, as: UTF8.self).replacingOccurrences(of: "\n", with: " "))") + + let openVPNConfig = try JSONDecoder().decode(OpenVPNConfig.self, from: openVPNConfigData) + log(.info, message: "openVPNConfig: \(openVPNConfig.str.replacingOccurrences(of: "\n", with: " "))") + let ovpnConfiguration = Data(openVPNConfig.config.utf8) + setupAndlaunchOpenVPN(withConfig: ovpnConfiguration, completionHandler: completionHandler) + } catch { + log(.error, message: "Can't parse OpenVPN config: \(error.localizedDescription)") + + if let underlyingError = (error as NSError).userInfo[NSUnderlyingErrorKey] as? NSError { + log(.error, message: "Can't parse OpenVPN config: \(underlyingError.localizedDescription)") + } + + return + } } private func stopWireguard(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { diff --git a/client/platforms/ios/WGConfig.swift b/client/platforms/ios/WGConfig.swift index 9593d289..15f99100 100644 --- a/client/platforms/ios/WGConfig.swift +++ b/client/platforms/ios/WGConfig.swift @@ -1,10 +1,41 @@ import Foundation -struct WGConfigData: Decodable { +struct WGConfig: Decodable { let initPacketMagicHeader, responsePacketMagicHeader: String? let underloadPacketMagicHeader, transportPacketMagicHeader: String? let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String? let initPacketJunkSize, responsePacketJunkSize: String? + let dns1: String + let dns2: String + let hostName: String + let port: Int + let clientIP: String + let clientPrivateKey: String + let serverPublicKey: String + let presharedKey: String + var allowedIPs: [String] + var persistentKeepAlive: String + let splitTunnelType: Int + let splitTunnelSites: [String] + + enum CodingKeys: String, CodingKey { + case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2" + case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4" + case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax" + case initPacketJunkSize = "S1", responsePacketJunkSize = "S2" + case dns1 + case dns2 + case hostName + case port + case clientIP = "client_ip" + case clientPrivateKey = "client_priv_key" + case serverPublicKey = "server_pub_key" + case presharedKey = "psk_key" + case allowedIPs = "allowed_ips" + case persistentKeepAlive = "persistent_keep_alive" + case splitTunnelType + case splitTunnelSites + } var settings: String { junkPacketCount == nil ? "" : @@ -22,114 +53,45 @@ struct WGConfigData: Decodable { """ } - let clientIP: String - let clientPrivateKey: String - let clientPublicKey: String - let serverPublicKey: String - let presharedKey: String - let hostName: String - let port: Int - - var allowedIPs: [String] - var persistentKeepAlive: String - - enum CodingKeys: String, CodingKey { - case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2" - case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4" - case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax" - case initPacketJunkSize = "S1", responsePacketJunkSize = "S2" - - case clientIP = "client_ip" // "10.8.1.16" - case clientPrivateKey = "client_priv_key" - case clientPublicKey = "client_pub_key" - case serverPublicKey = "server_pub_key" - case presharedKey = "psk_key" - - case allowedIPs = "allowed_ips" - case persistentKeepAlive = "persistent_keep_alive" - case hostName - case port - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.initPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .initPacketMagicHeader) - self.responsePacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .responsePacketMagicHeader) - self.underloadPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .underloadPacketMagicHeader) - self.transportPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .transportPacketMagicHeader) - self.junkPacketCount = try container.decodeIfPresent(String.self, forKey: .junkPacketCount) - self.junkPacketMinSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMinSize) - self.junkPacketMaxSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMaxSize) - self.initPacketJunkSize = try container.decodeIfPresent(String.self, forKey: .initPacketJunkSize) - self.responsePacketJunkSize = try container.decodeIfPresent(String.self, forKey: .responsePacketJunkSize) - self.clientIP = try container.decode(String.self, forKey: .clientIP) - self.clientPrivateKey = try container.decode(String.self, forKey: .clientPrivateKey) - self.clientPublicKey = try container.decode(String.self, forKey: .clientPublicKey) - self.serverPublicKey = try container.decode(String.self, forKey: .serverPublicKey) - self.presharedKey = try container.decode(String.self, forKey: .presharedKey) - self.allowedIPs = try container.decodeIfPresent([String].self, forKey: .allowedIPs) ?? ["0.0.0.0/0", "::/0"] - self.persistentKeepAlive = try container.decodeIfPresent(String.self, forKey: .persistentKeepAlive) ?? "25" - self.hostName = try container.decode(String.self, forKey: .hostName) - self.port = try container.decode(Int.self, forKey: .port) - } -} - -struct WGConfig: Decodable { - let data: WGConfigData - let configVersion: Int - let description: String - let dns1: String - let dns2: String - let hostName: String - let `protocol`: String - let splitTunnelSites: [String] - let splitTunnelType: Int - - enum CodingKeys: String, CodingKey { - case awgConfigData = "awg_config_data", wgConfigData = "wireguard_config_data" - case configData - case configVersion = "config_version" - case description - case dns1 - case dns2 - case hostName - case `protocol` - case splitTunnelSites - case splitTunnelType - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - if container.contains(.awgConfigData) { - self.data = try container.decode(WGConfigData.self, forKey: .awgConfigData) - } else { - self.data = try container.decode(WGConfigData.self, forKey: .wgConfigData) - } - - self.configVersion = try container.decode(Int.self, forKey: .configVersion) - self.description = try container.decode(String.self, forKey: .description) - self.dns1 = try container.decode(String.self, forKey: .dns1) - self.dns2 = try container.decode(String.self, forKey: .dns2) - self.hostName = try container.decode(String.self, forKey: .hostName) - self.protocol = try container.decode(String.self, forKey: .protocol) - self.splitTunnelSites = try container.decode([String].self, forKey: .splitTunnelSites) - self.splitTunnelType = try container.decode(Int.self, forKey: .splitTunnelType) - } - var str: String { """ [Interface] - Address = \(data.clientIP)/32 + Address = \(clientIP) DNS = \(dns1), \(dns2) - PrivateKey = \(data.clientPrivateKey) - \(data.settings) + PrivateKey = \(clientPrivateKey) + \(settings) [Peer] - PublicKey = \(data.serverPublicKey) - PresharedKey = \(data.presharedKey) - AllowedIPs = \(data.allowedIPs.joined(separator: ", ")) - Endpoint = \(data.hostName):\(data.port) - PersistentKeepalive = \(data.persistentKeepAlive) + PublicKey = \(serverPublicKey) + PresharedKey = \(presharedKey) + AllowedIPs = \(allowedIPs.joined(separator: ", ")) + Endpoint = \(hostName):\(port) + PersistentKeepalive = \(persistentKeepAlive) + """ + } + + var redux: String { + """ + [Interface] + Address = \(clientIP) + DNS = \(dns1), \(dns2) + PrivateKey = *** + \(settings) + [Peer] + PublicKey = *** + PresharedKey = *** + AllowedIPs = \(allowedIPs.joined(separator: ", ")) + Endpoint = \(hostName):\(port) + PersistentKeepalive = \(persistentKeepAlive) """ } } + +struct OpenVPNConfig: Decodable { + let config: String + let splitTunnelType: Int + let splitTunnelSites: [String] + + var str: String { + "splitTunnelType: \(splitTunnelType) splitTunnelSites: \(splitTunnelSites) config: \(config)" + } +} diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index 0d5eadbc..b8ce0372 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -235,7 +235,6 @@ void IosController::checkStatus() m_rxBytes = rxBytes; m_txBytes = txBytes; }); - } void IosController::vpnStatusDidChange(void *pNotification) @@ -244,13 +243,13 @@ void IosController::vpnStatusDidChange(void *pNotification) if (session /* && session == TunnelManager.session */ ) { qDebug() << "IosController::vpnStatusDidChange" << iosStatusToState(session.status) << session; - + if (session.status == NEVPNStatusDisconnected) { if (@available(iOS 16.0, *)) { [session fetchLastDisconnectErrorWithCompletionHandler:^(NSError * _Nullable error) { if (error != nil) { qDebug() << "Disconnect error" << error.domain << error.code << error.localizedDescription; - + if ([error.domain isEqualToString:NEVPNConnectionErrorDomain]) { switch (error.code) { case NEVPNConnectionErrorOverslept: @@ -315,11 +314,11 @@ void IosController::vpnStatusDidChange(void *pNotification) break; } } - + NSError *underlyingError = error.userInfo[@"NSUnderlyingError"]; if (underlyingError != nil) { qDebug() << "Disconnect underlying error" << underlyingError.domain << underlyingError.code << underlyingError.localizedDescription; - + if ([underlyingError.domain isEqualToString:@"NEAgentErrorDomain"]) { switch (underlyingError.code) { case 1: @@ -342,7 +341,7 @@ void IosController::vpnStatusDidChange(void *pNotification) qDebug() << "Disconnect error is unavailable on iOS < 16.0"; } } - + emit connectionStateChanged(iosStatusToState(session.status)); } } @@ -357,7 +356,22 @@ bool IosController::setupOpenVPN() QJsonObject ovpn = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::OpenVpn)].toObject(); QString ovpnConfig = ovpn[config_key::config].toString(); - return startOpenVPN(ovpnConfig); + QJsonObject openVPNConfig {}; + openVPNConfig.insert(config_key::config, ovpnConfig); + openVPNConfig.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(" "); + } + + openVPNConfig.insert(config_key::splitTunnelSites, splitTunnelSites); + + QJsonDocument openVPNConfigDoc(openVPNConfig); + QString openVPNConfigStr(openVPNConfigDoc.toJson(QJsonDocument::Compact)); + + return startOpenVPN(openVPNConfigStr); } bool IosController::setupCloak() @@ -394,27 +408,123 @@ bool IosController::setupCloak() ovpnConfig.append(cloakBase64); ovpnConfig.append("\n\n"); - return startOpenVPN(ovpnConfig); + QJsonObject openVPNConfig {}; + openVPNConfig.insert(config_key::config, ovpnConfig); + openVPNConfig.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(" "); + } + + openVPNConfig.insert(config_key::splitTunnelSites, splitTunnelSites); + + QJsonDocument openVPNConfigDoc(openVPNConfig); + QString openVPNConfigStr(openVPNConfigDoc.toJson(QJsonDocument::Compact)); + + return startOpenVPN(openVPNConfigStr); } bool IosController::setupWireGuard() { QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject(); - - QJsonDocument doc(m_rawConfig); - QString wgConfig(doc.toJson(QJsonDocument::Compact)); - return startWireGuard(wgConfig); + QJsonObject wgConfig {}; + wgConfig.insert(config_key::dns1, m_rawConfig[config_key::dns1]); + wgConfig.insert(config_key::dns2, m_rawConfig[config_key::dns2]); + wgConfig.insert(config_key::hostName, config[config_key::hostName]); + wgConfig.insert(config_key::port, config[config_key::port]); + wgConfig.insert(config_key::client_ip, config[config_key::client_ip]); + wgConfig.insert(config_key::client_priv_key, config[config_key::client_priv_key]); + wgConfig.insert(config_key::server_pub_key, config[config_key::server_pub_key]); + wgConfig.insert(config_key::psk_key, config[config_key::psk_key]); + wgConfig.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(" "); + } + + wgConfig.insert(config_key::splitTunnelSites, splitTunnelSites); + + if (config.contains(config_key::allowed_ips)) { + QJsonArray allowed_ips; + QStringList allowed_ips_list = config[config_key::allowed_ips].toString().split(", "); + + for(int index = 0; index < allowed_ips_list.length(); index++) { + allowed_ips.append(allowed_ips_list[index]); + } + + wgConfig.insert(config_key::allowed_ips, allowed_ips); + } else { + QJsonArray allowed_ips { "0.0.0.0/0", "::/0" }; + wgConfig.insert(config_key::allowed_ips, allowed_ips); + } + + wgConfig.insert("persistent_keep_alive", "25"); + + QJsonDocument wgConfigDoc(wgConfig); + QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact)); + + return startWireGuard(wgConfigDocStr); } bool IosController::setupAwg() { QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject(); - QJsonDocument doc(m_rawConfig); - QString wgConfig(doc.toJson(QJsonDocument::Compact)); + QJsonObject wgConfig {}; + wgConfig.insert(config_key::dns1, m_rawConfig[config_key::dns1]); + wgConfig.insert(config_key::dns2, m_rawConfig[config_key::dns2]); + wgConfig.insert(config_key::hostName, config[config_key::hostName]); + wgConfig.insert(config_key::port, config[config_key::port]); + wgConfig.insert(config_key::client_ip, config[config_key::client_ip]); + wgConfig.insert(config_key::client_priv_key, config[config_key::client_priv_key]); + wgConfig.insert(config_key::server_pub_key, config[config_key::server_pub_key]); + wgConfig.insert(config_key::psk_key, config[config_key::psk_key]); + wgConfig.insert(config_key::splitTunnelType, m_rawConfig[config_key::splitTunnelType]); - return startWireGuard(wgConfig); + QJsonArray splitTunnelSites = m_rawConfig[config_key::splitTunnelSites].toArray(); + + for(int index = 0; index < splitTunnelSites.count(); index++) { + splitTunnelSites[index] = splitTunnelSites[index].toString().remove(" "); + } + + wgConfig.insert(config_key::splitTunnelSites, splitTunnelSites); + + if (config.contains(config_key::allowed_ips)) { + QJsonArray allowed_ips; + QStringList allowed_ips_list = config[config_key::allowed_ips].toString().split(", "); + + for(int index = 0; index < allowed_ips_list.length(); index++) { + allowed_ips.append(allowed_ips_list[index]); + } + + wgConfig.insert(config_key::allowed_ips, allowed_ips); + } else { + QJsonArray allowed_ips { "0.0.0.0/0", "::/0" }; + wgConfig.insert(config_key::allowed_ips, allowed_ips); + } + + wgConfig.insert("persistent_keep_alive", "25"); + 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)); + + return startWireGuard(wgConfigDocStr); } bool IosController::startOpenVPN(const QString &config) @@ -448,23 +558,17 @@ bool IosController::startWireGuard(const QString &config) void IosController::startTunnel() { NSString *protocolName = @"Unknown"; - + NETunnelProviderProtocol *tunnelProtocol = (NETunnelProviderProtocol *)m_currentTunnel.protocolConfiguration; if (tunnelProtocol.providerConfiguration[@"wireguard"] != nil) { protocolName = @"WireGuard"; } else if (tunnelProtocol.providerConfiguration[@"ovpn"] != nil) { protocolName = @"OpenVPN"; } - + m_rxBytes = 0; m_txBytes = 0; - - int STT = m_rawConfig["splitTunnelType"].toInt(); - QJsonArray splitTunnelSites = m_rawConfig["splitTunnelSites"].toArray(); - QJsonDocument doc; - doc.setArray(splitTunnelSites); - QString STS(doc.toJson()); - + [m_currentTunnel setEnabled:YES]; [m_currentTunnel saveToPreferencesWithCompletionHandler:^(NSError *saveError) { @@ -485,23 +589,6 @@ void IosController::startTunnel() NSError *startError = nil; qDebug() << iosStatusToState(m_currentTunnel.connection.status); - - NSString *actionKey = [NSString stringWithUTF8String:MessageKey::action]; - NSString *actionValue = [NSString stringWithUTF8String:Action::start]; - NSString *tunnelIdKey = [NSString stringWithUTF8String:MessageKey::tunnelId]; - NSString *tunnelIdValue = !m_tunnelId.isEmpty() ? m_tunnelId.toNSString() : @""; - NSString *SplitTunnelTypeKey = [NSString stringWithUTF8String:MessageKey::SplitTunnelType]; - NSString *SplitTunnelTypeValue = [NSString stringWithFormat:@"%d",STT]; - NSString *SplitTunnelSitesKey = [NSString stringWithUTF8String:MessageKey::SplitTunnelSites]; - NSString *SplitTunnelSitesValue = STS.toNSString(); - - - NSDictionary* message = @{actionKey: actionValue, tunnelIdKey: tunnelIdValue, - SplitTunnelTypeKey: SplitTunnelTypeValue, SplitTunnelSitesKey: SplitTunnelSitesValue}; - - sendVpnExtensionMessage(message); - - BOOL started = [m_currentTunnel.connection startVPNTunnelWithOptions:nil andReturnError:&startError]; if (!started || startError) { @@ -516,7 +603,6 @@ void IosController::startTunnel() }]; } - bool IosController::isOurManager(NETunnelProviderManager* manager) { NETunnelProviderProtocol* tunnelProto = (NETunnelProviderProtocol*)manager.protocolConfiguration; @@ -578,7 +664,7 @@ void IosController::sendVpnExtensionMessage(NSDictionary* message, std::function NETunnelProviderSession *session = (NETunnelProviderSession *)m_currentTunnel.connection; NSError *sendError = nil; - + if ([session respondsToSelector:@selector(sendProviderMessage:returnError:responseHandler:)]) { [session sendProviderMessage:data returnError:&sendError responseHandler:completionHandler]; } else {