diff --git a/.gitignore b/.gitignore index 2ead399d..ab38a962 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ client/amneziavpn_qml_plugin_import.cpp client/qmlcache_loader.cpp client/rep_ipc_interface_replica.h client/resources_qmlcache.qrc +client/3rd/OpenVPNAdpter/build/ # QtCreator diff --git a/.gitmodules b/.gitmodules index 30d8d61d..712c21f9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "client/3rd/wireguard-apple"] path = client/3rd/wireguard-apple url = https://github.com/WireGuard/wireguard-apple +[submodule "client/3rd/OpenVPNAdapter"] + path = client/3rd/OpenVPNAdapter + url = https://github.com/ss-abramchuk/OpenVPNAdapter.git diff --git a/client/3rd/OpenVPNAdapter b/client/3rd/OpenVPNAdapter new file mode 160000 index 00000000..0e2db0ba --- /dev/null +++ b/client/3rd/OpenVPNAdapter @@ -0,0 +1 @@ +Subproject commit 0e2db0baa0d66029cbb18d74b78bc7a5c9013fba diff --git a/client/AmneziaVPN-Swift.h b/client/AmneziaVPN-Swift.h index c04ce421..5fa52612 100644 --- a/client/AmneziaVPN-Swift.h +++ b/client/AmneziaVPN-Swift.h @@ -217,7 +217,9 @@ enum ConnectionState : NSInteger; SWIFT_CLASS("_TtC10AmneziaVPN18IOSVpnProtocolImpl") @interface IOSVpnProtocolImpl : NSObject - (nonnull instancetype)initWithBundleID:(NSString * _Nonnull)bundleID privateKey:(NSData * _Nonnull)privateKey deviceIpv4Address:(NSString * _Nonnull)deviceIpv4Address deviceIpv6Address:(NSString * _Nonnull)deviceIpv6Address closure:(void (^ _Nonnull)(enum ConnectionState, NSDate * _Nullable))closure callback:(void (^ _Nonnull)(BOOL))callback OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithBundleID:(NSString * _Nonnull)bundleID config:(NSString * _Nonnull)config closure:(void (^ _Nonnull)(enum ConnectionState, NSDate * _Nullable))closure callback:(void (^ _Nonnull)(BOOL))callback; - (void)connectWithDnsServer:(NSString * _Nonnull)dnsServer serverIpv6Gateway:(NSString * _Nonnull)serverIpv6Gateway serverPublicKey:(NSString * _Nonnull)serverPublicKey presharedKey:(NSString * _Nonnull)presharedKey serverIpv4AddrIn:(NSString * _Nonnull)serverIpv4AddrIn serverPort:(NSInteger)serverPort allowedIPAddressRanges:(NSArray * _Nonnull)allowedIPAddressRanges ipv6Enabled:(Boolean)enabled reason:(NSInteger)reason failureCallback:(void (^ _Nonnull)(void))failureCallback; +- (void)connectWithOvpnConfig:(NSString * _Nonnull)ovpnConfig failureCallback:(void (^ _Nonnull)(void))failureCallback; - (void)disconnect; - (void)checkStatusWithCallback:(void (^ _Nonnull)(NSString * _Nonnull, NSString * _Nonnull, NSString * _Nonnull))callback; - (nonnull instancetype)init SWIFT_UNAVAILABLE; @@ -230,8 +232,6 @@ typedef SWIFT_ENUM(NSInteger, ConnectionState, closed) { ConnectionStateDisconnected = 2, }; - - SWIFT_CLASS("_TtC10AmneziaVPN17VPNIPAddressRange") @interface VPNIPAddressRange : NSObject - (nonnull instancetype)initWithAddress:(NSString * _Nonnull)address networkPrefixLength:(uint8_t)networkPrefixLength isIpv6:(BOOL)isIpv6 OBJC_DESIGNATED_INITIALIZER; diff --git a/client/client.pro b/client/client.pro index 489edd4f..84354e1a 100644 --- a/client/client.pro +++ b/client/client.pro @@ -276,6 +276,11 @@ ios { LIBS += -framework StoreKit LIBS += -framework UserNotifications +# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/LZ4.framework +# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/mbedTLS.framework +# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNClient.framework +# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNAdapter.framework + DEFINES += MVPN_IOS HEADERS += \ @@ -309,7 +314,7 @@ ios { QMAKE_DEVELOPMENT_TEAM = X7UJ388FXK QMAKE_PROVISIONING_PROFILE = f2fefb59-14aa-4aa9-ac14-1d5531b06dcc QMAKE_XCODE_CODE_SIGN_IDENTITY = "Apple Distribution" - QMAKE_INFO_PLIST= $$PWD/ios/app/Info.plist + QMAKE_INFO_PLIST = $$PWD/ios/app/Info.plist XCODEBUILD_FLAGS += -allowProvisioningUpdates diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index 0c72e4a7..63a00e0b 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -136,3 +136,32 @@ Proto ContainerProps::defaultProtocol(DockerContainer c) } } +bool ContainerProps::isWorkingOnPlatform(DockerContainer c) +{ +#ifdef Q_OS_WINDOWS + return true; + +#elif defined (Q_OS_IOS) + switch (c) { + case DockerContainer::WireGuard: return true; + case DockerContainer::OpenVpn: return true; + default: return false; + } +#elif defined (Q_OS_MAC) + return false; + +#elif defined (Q_OS_ANDROID) + switch (c) { + case DockerContainer::WireGuard: return true; + case DockerContainer::OpenVpn: return true; + default: return false; + } + +#elif defined (Q_OS_LINUX) + return false; + +#else +return false; +#endif +} + diff --git a/client/containers/containers_defs.h b/client/containers/containers_defs.h index c2cf5b7d..0fd1ce4a 100644 --- a/client/containers/containers_defs.h +++ b/client/containers/containers_defs.h @@ -53,6 +53,8 @@ public: // binding between Docker container and main protocol of given container // it may be changed fot future containers :) Q_INVOKABLE static Proto defaultProtocol(DockerContainer c); + + Q_INVOKABLE static bool isWorkingOnPlatform(DockerContainer c); }; diff --git a/client/platforms/ios/iostunnel.swift b/client/platforms/ios/iostunnel.swift index a316d054..888d17d2 100644 --- a/client/platforms/ios/iostunnel.swift +++ b/client/platforms/ios/iostunnel.swift @@ -4,94 +4,72 @@ import Foundation import NetworkExtension import os +import OpenVPNAdapter + +enum TunnelProtoType: String { + case wireguard, openvpn, none +} class PacketTunnelProvider: NEPacketTunnelProvider { - + private lazy var wgAdapter: WireGuardAdapter = { return WireGuardAdapter(with: self) { logLevel, message in wg_log(logLevel.osLogLevel, message: message) } }() + + private lazy var ovpnAdapter: OpenVPNAdapter = { + let adapter = OpenVPNAdapter() + adapter.delegate = self + return adapter + }() + + let vpnReachability = OpenVPNReachability() + var startHandler: ((Error?) -> Void)? + var stopHandler: (() -> Void)? + var protoType: TunnelProtoType = .wireguard + override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { let activationAttemptId = options?["activationAttemptId"] as? String let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId) - + Logger.configureGlobal(tagged: "NET", withFilePath: FileManager.logFileURL?.path) - - wg_log(.info, message: "Starting tunnel from the " + (activationAttemptId == nil ? "OS directly, rather than the app" : "app")) - - guard let tunnelProviderProtocol = self.protocolConfiguration as? NETunnelProviderProtocol, - let tunnelConfiguration = tunnelProviderProtocol.asTunnelConfiguration() else { - errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid) - completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid) - return + + if let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol, + let providerConfiguration = protocolConfiguration.providerConfiguration, + let _: Data = providerConfiguration["ovpn"] as? Data { + protoType = .openvpn + } else { + protoType = .wireguard } - - // Start the tunnel - wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in - guard let adapterError = 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: - // Must never happen - fatalError() - } + + switch protoType { + case .wireguard: + startWireguard(activationAttemptId: activationAttemptId, + errorNotifier: errorNotifier, + completionHandler: completionHandler) + case .openvpn: + startOpenVPN(completionHandler: completionHandler) + case .none: + break } } - + override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { - wg_log(.info, staticMessage: "Stopping tunnel") - - wgAdapter.stop { error in - ErrorNotifier.removeLastErrorFile() - - if let error = error { - wg_log(.error, message: "Failed to stop WireGuard adapter: \(error.localizedDescription)") - } - completionHandler() - - #if os(macOS) - // HACK: This is a filthy hack to work around Apple bug 32073323 (dup'd by us as 47526107). - // Remove it when they finally fix this upstream and the fix has been rolled out to - // sufficient quantities of users. - exit(0) - #endif + switch protoType { + case .wireguard: + stopWireguard(with: reason, completionHandler: completionHandler) + case .openvpn: + stopOpenVPN(with: reason, completionHandler: completionHandler) + case .none: + break } } - + override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) { guard let completionHandler = completionHandler else { return } - + if messageData.count == 1 && messageData[0] == 0 { wgAdapter.getRuntimeConfiguration { settings in var data: Data? @@ -108,31 +86,144 @@ class PacketTunnelProvider: NEPacketTunnelProvider { completionHandler(nil) return } - + do { - let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString) - wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in - if let error = error { - wg_log(.error, message: "Failed to switch tunnel configuration: \(error.localizedDescription)") - completionHandler(nil) - return + let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString) + wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in + if let error = error { + wg_log(.error, message: "Failed to switch tunnel configuration: \(error.localizedDescription)") + completionHandler(nil) + return + } + + self.wgAdapter.getRuntimeConfiguration { settings in + var data: Data? + if let settings = settings { + data = settings.data(using: .utf8)! + } + completionHandler(data) + } } - - self.wgAdapter.getRuntimeConfiguration { settings in - var data: Data? - if let settings = settings { - data = settings.data(using: .utf8)! - } - completionHandler(data) - } - } } catch { - completionHandler(nil) + completionHandler(nil) } } else { completionHandler(nil) } } + + // MARK: Private methods + private func startWireguard(activationAttemptId: String?, + errorNotifier: ErrorNotifier, + completionHandler: @escaping (Error?) -> Void) { + guard let tunnelProviderProtocol = self.protocolConfiguration as? NETunnelProviderProtocol, + let tunnelConfiguration = tunnelProviderProtocol.asTunnelConfiguration() else { + errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid) + completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid) + return + } + 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 = 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: + // Must never happen + fatalError() + } + } + } + + private func startOpenVPN(completionHandler: @escaping (Error?) -> Void) { + guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol, + let providerConfiguration = protocolConfiguration.providerConfiguration, + let ovpnConfiguration: Data = providerConfiguration["ovpn"] as? Data else { + return + } + + let configuration = OpenVPNConfiguration() + configuration.fileContent = ovpnConfiguration +// configuration.settings = [] // Additional setting if needed any +// configuration.tunPersist = true // keep tun active during pauses/reconections + let evaluation: OpenVPNConfigurationEvaluation + do { + evaluation = try ovpnAdapter.apply(configuration: configuration) + } catch { + completionHandler(error) + return + } + + if !evaluation.autologin { + print("Implement login with user credentials") + } + + vpnReachability.startTracking { [weak self] status in + guard status == .reachableViaWiFi else { return } + self?.ovpnAdapter.reconnect(afterTimeInterval: 5) + } + + startHandler = completionHandler + ovpnAdapter.connect(using: packetFlow) + } + + private func stopWireguard(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + wg_log(.info, staticMessage: "Stopping tunnel") + + wgAdapter.stop { error in + ErrorNotifier.removeLastErrorFile() + + if let error = error { + wg_log(.error, message: "Failed to stop WireGuard adapter: \(error.localizedDescription)") + } + completionHandler() + +#if os(macOS) + // HACK: This is a filthy hack to work around Apple bug 32073323 (dup'd by us as 47526107). + // Remove it when they finally fix this upstream and the fix has been rolled out to + // sufficient quantities of users. + exit(0) +#endif + } + } + + private func stopOpenVPN(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + stopHandler = completionHandler + if vpnReachability.isTracking { + vpnReachability.stopTracking() + } + ovpnAdapter.disconnect() + } } extension WireGuardLogLevel { @@ -145,3 +236,87 @@ extension WireGuardLogLevel { } } } + +extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {} + +extension PacketTunnelProvider: OpenVPNAdapterDelegate { + + // OpenVPNAdapter calls this delegate method to configure a VPN tunnel. + // `completionHandler` callback requires an object conforming to `OpenVPNAdapterPacketFlow` + // protocol if the tunnel is configured without errors. Otherwise send nil. + // `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so + // you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and + // send `self.packetFlow` to `completionHandler` callback. + func openVPNAdapter( + _ openVPNAdapter: OpenVPNAdapter, + configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, + completionHandler: @escaping (Error?) -> Void + ) { + // In order to direct all DNS queries first to the VPN DNS servers before the primary DNS servers + // send empty string to NEDNSSettings.matchDomains + networkSettings?.dnsSettings?.matchDomains = [""] + + // Set the network settings for the current tunneling session. + setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler) + } + + // Process events returned by the OpenVPN library + func openVPNAdapter( + _ openVPNAdapter: OpenVPNAdapter, + handleEvent event: + OpenVPNAdapterEvent, message: String? + ) { + switch event { + case .connected: + if reasserting { + reasserting = false + } + + guard let startHandler = startHandler else { return } + + startHandler(nil) + self.startHandler = nil + + case .disconnected: + guard let stopHandler = stopHandler else { return } + + if vpnReachability.isTracking { + vpnReachability.stopTracking() + } + + stopHandler() + self.stopHandler = nil + + case .reconnecting: + reasserting = true + + default: + break + } + } + + // Handle errors thrown by the OpenVPN library + func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleError error: Error) { + // Handle only fatal errors + guard let fatal = (error as NSError).userInfo[OpenVPNAdapterErrorFatalKey] as? Bool, + fatal == true else { return } + + if vpnReachability.isTracking { + vpnReachability.stopTracking() + } + + if let startHandler = startHandler { + startHandler(error) + self.startHandler = nil + } else { + cancelTunnelWithError(error) + } + } + + // Use this method to process any log message returned by OpenVPN library. + func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) { + // Handle log messages + } +} + + diff --git a/client/platforms/ios/iosvpnprotocol.swift b/client/platforms/ios/iosvpnprotocol.swift index ce0363e7..67876193 100644 --- a/client/platforms/ios/iosvpnprotocol.swift +++ b/client/platforms/ios/iosvpnprotocol.swift @@ -5,7 +5,7 @@ import Foundation import NetworkExtension -let vpnName = "AmneziaVPN" +let vpnName = "Amnezia WireguardVPN" var vpnBundleID = ""; @objc class VPNIPAddressRange : NSObject { @@ -30,27 +30,32 @@ public class IOSVpnProtocolImpl : NSObject { private var deviceIpv4Address: String? = nil private var deviceIpv6Address: String? = nil - @objc enum IOSConnectionState: Int { case Error, Connected, Disconnected } - - @objc init(bundleID: String, privateKey: Data, deviceIpv4Address: String, deviceIpv6Address: String, closure: @escaping (IOSConnectionState, Date?) -> Void, callback: @escaping (Bool) -> Void) { + @objc enum ConnectionState: Int { case Error, Connected, Disconnected } + + @objc init(bundleID: String, + config: String, + closure: @escaping (ConnectionState, Date?) -> Void, + callback: @escaping (Bool) -> Void) { super.init() - Logger.configureGlobal(tagged: "APP", withFilePath: "") + + print("Config from caller: \(config)") vpnBundleID = bundleID; precondition(!vpnBundleID.isEmpty) - + stateChangeCallback = callback - self.privateKey = PrivateKey(rawValue: privateKey) - self.deviceIpv4Address = deviceIpv4Address - self.deviceIpv6Address = deviceIpv6Address - - NotificationCenter.default.addObserver(self, selector: #selector(self.vpnStatusDidChange(notification:)), name: Notification.Name.NEVPNStatusDidChange, object: nil) + + + NotificationCenter.default.addObserver(self, + selector: #selector(self.vpnStatusDidChange(notification:)), + name: Notification.Name.NEVPNStatusDidChange, + object: nil) NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in if let error = error { Logger.global?.log(message: "Loading from preference failed: \(error)") - closure(IOSConnectionState.Error, nil) + closure(ConnectionState.Error, nil) return } @@ -64,11 +69,22 @@ public class IOSVpnProtocolImpl : NSObject { print("We have received \(nsManagers.count) managers.") let tunnel = nsManagers.first(where: IOSVpnProtocolImpl.isOurManager(_:)) + + if let name = tunnel?.localizedDescription, name == vpnName { + tunnel?.removeFromPreferences(completionHandler: { removeError in + if let error = removeError { + Logger.global?.log(message: "WireguardVPN Tunnel Remove from Prefs Error: \(error)") + closure(ConnectionState.Error, nil) + return + } + }) + } + if tunnel == nil { Logger.global?.log(message: "Creating the tunnel") print("Creating the tunnel") self!.tunnel = NETunnelProviderManager() - closure(IOSConnectionState.Disconnected, nil) + closure(ConnectionState.Disconnected, nil) return } @@ -77,9 +93,78 @@ public class IOSVpnProtocolImpl : NSObject { self!.tunnel = tunnel if tunnel?.connection.status == .connected { - closure(IOSConnectionState.Connected, tunnel?.connection.connectedDate) + closure(ConnectionState.Connected, tunnel?.connection.connectedDate) } else { - closure(IOSConnectionState.Disconnected, nil) + closure(ConnectionState.Disconnected, nil) + } + } + } + + @objc init(bundleID: String, + privateKey: Data, + deviceIpv4Address: String, + deviceIpv6Address: String, + closure: @escaping (ConnectionState, Date?) -> Void, + callback: @escaping (Bool) -> Void) { + super.init() + + Logger.configureGlobal(tagged: "APP", withFilePath: "") + + vpnBundleID = bundleID; + precondition(!vpnBundleID.isEmpty) + + stateChangeCallback = callback + self.privateKey = PrivateKey(rawValue: privateKey) + self.deviceIpv4Address = deviceIpv4Address + self.deviceIpv6Address = deviceIpv6Address + + NotificationCenter.default.addObserver(self, selector: #selector(self.vpnStatusDidChange(notification:)), name: Notification.Name.NEVPNStatusDidChange, object: nil) + + NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in + if let error = error { + Logger.global?.log(message: "Loading from preference failed: \(error)") + closure(ConnectionState.Error, nil) + return + } + + if self == nil { + Logger.global?.log(message: "We are shutting down.") + return + } + + let nsManagers = managers ?? [] + Logger.global?.log(message: "We have received \(nsManagers.count) managers.") + print("We have received \(nsManagers.count) managers.") + + let tunnel = nsManagers.first(where: IOSVpnProtocolImpl.isOurManager(_:)) + + if let name = tunnel?.localizedDescription, name != vpnName { + tunnel?.removeFromPreferences(completionHandler: { removeError in + if let error = removeError { + Logger.global?.log(message: "OpenVpn Tunnel Remove from Prefs Error: \(error)") + closure(ConnectionState.Error, nil) + return + } + }) + } + + if tunnel == nil { + Logger.global?.log(message: "Creating the tunnel") + print("Creating the tunnel") + self!.tunnel = NETunnelProviderManager() + closure(ConnectionState.Disconnected, nil) + return + } + + Logger.global?.log(message: "Tunnel already exists") + print("Tunnel already exists") + + self!.tunnel = tunnel + + if tunnel?.connection.status == .connected { + closure(ConnectionState.Connected, tunnel?.connection.connectedDate) + } else { + closure(ConnectionState.Disconnected, nil) } } } @@ -142,6 +227,22 @@ public class IOSVpnProtocolImpl : NSObject { print("Found the manager with the correct bundle identifier: \(tunnelProto.providerBundleIdentifier!)") return true } + + @objc func connect(ovpnConfig: String, failureCallback: @escaping () -> Void) { + Logger.global?.log(message: "Connecting") + assert(tunnel != nil) + + let addr: String = ovpnConfig + .splitToArray(separator: "\n", trimmingCharacters: nil) + .first { $0.starts(with: "remote ") } + .splitToArray(separator: " ", trimmingCharacters: nil)[1] + print("server: \(addr)") + + // Let's remove the previous config if it exists. + (tunnel?.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference() + + self.configureOpenVPNTunnel(serverAddress: addr, config: ovpnConfig, failureCallback: failureCallback) + } @objc func connect(dnsServer: String, serverIpv6Gateway: String, serverPublicKey: String, presharedKey: String, serverIpv4AddrIn: String, serverPort: Int, allowedIPAddressRanges: Array, ipv6Enabled: Bool, reason: Int, failureCallback: @escaping () -> Void) { Logger.global?.log(message: "Connecting") @@ -247,6 +348,46 @@ public class IOSVpnProtocolImpl : NSObject { } } } + + func configureOpenVPNTunnel(serverAddress: String, config: String, failureCallback: @escaping () -> Void) { + let tunnelProtocol = NETunnelProviderProtocol() + tunnelProtocol.serverAddress = serverAddress + tunnelProtocol.providerBundleIdentifier = vpnBundleID + tunnelProtocol.providerConfiguration = ["ovpn": Data(config.utf8)] + tunnel?.protocolConfiguration = tunnelProtocol + tunnel?.localizedDescription = "Amnezia OpenVPN" + tunnel?.isEnabled = true + + tunnel?.saveToPreferences { [unowned self] saveError in + if let error = saveError { + Logger.global?.log(message: "Connect OpenVPN Tunnel Save Error: \(error)") + failureCallback() + return + } + + Logger.global?.log(message: "Saving the OpenVPN tunnel succeeded") + + self.tunnel?.loadFromPreferences { error in + if let error = error { + Logger.global?.log(message: "Connect OpenVPN Tunnel Load Error: \(error)") + failureCallback() + return + } + + Logger.global?.log(message: "Loading the OpenVPN tunnel succeeded") + print("Loading the openvpn tunnel succeeded") + + do { + print("starting openvpn tunnel") + try self.tunnel?.connection.startVPNTunnel() + } catch let error { + Logger.global?.log(message: "Something went wrong: \(error)") + failureCallback() + return + } + } + } + } @objc func disconnect() { Logger.global?.log(message: "Disconnecting") @@ -257,7 +398,74 @@ public class IOSVpnProtocolImpl : NSObject { @objc func checkStatus(callback: @escaping (String, String, String) -> Void) { Logger.global?.log(message: "Check status") assert(tunnel != nil) + + let protoType = (tunnel!.localizedDescription ?? "").toTunnelType + + switch protoType { + case .wireguard: + checkWireguardStatus(callback: callback) + case .openvpn: + checkOVPNStatus(callback: callback) + case .empty: + break + } + + } + + private func checkOVPNStatus(callback: @escaping (String, String, String) -> Void) { + Logger.global?.log(message: "Check OpenVPN") + guard let proto = tunnel?.protocolConfiguration as? NETunnelProviderProtocol else { + callback("", "", "") + return + } + + guard let configData = proto.providerConfiguration?["ovpn"] as? Data, + let ovpnConfig = String(data: configData, encoding: .utf8) else { + callback("", "", "") + return + } + + let serverIpv4Gateway: String = ovpnConfig + .splitToArray(separator: "\n", trimmingCharacters: nil) + .first { $0.starts(with: "remote ") } + .splitToArray(separator: " ", trimmingCharacters: nil)[1] + + print("server IP: \(serverIpv4Gateway)") + + + let deviceIpv4Address = getTunIPAddress() + print("device IP: \(serverIpv4Gateway)") + if deviceIpv4Address == nil { + callback("", "", "") + return + } + + guard let session = tunnel?.connection as? NETunnelProviderSession else { + callback("", "", "") + return + } + + do { + try session.sendProviderMessage(Data([UInt8(0)])) { [callback] data in + guard let data = data, + let configString = String(data: data, encoding: .utf8) + else { + Logger.global?.log(message: "Failed to convert data to string") + callback("", "", "") + return + } + callback("\(serverIpv4Gateway)", "\(deviceIpv4Address!)", configString) + } + } catch { + Logger.global?.log(message: "Failed to retrieve data from session") + callback("", "", "") + } + + } + + private func checkWireguardStatus(callback: @escaping (String, String, String) -> Void) { + Logger.global?.log(message: "Check Wireguard") let proto = tunnel!.protocolConfiguration as? NETunnelProviderProtocol if proto == nil { callback("", "", "") @@ -305,4 +513,50 @@ public class IOSVpnProtocolImpl : NSObject { callback("", "", "") } } + + private func getTunIPAddress() -> String? { + var address: String? = nil + var interfaces: UnsafeMutablePointer? = nil + var temp_addr: UnsafeMutablePointer? = nil + var success: Int = 0 + + // retrieve the current interfaces - returns 0 on success + success = Int(getifaddrs(&interfaces)) + if success == 0 { + // Loop through linked list of interfaces + temp_addr = interfaces + while temp_addr != nil { + if temp_addr?.pointee.ifa_addr == nil { + continue + } + if temp_addr?.pointee.ifa_addr.pointee.sa_family == UInt8(AF_INET) { + // Check if interface is en0 which is the wifi connection on the iPhone + if let name = temp_addr?.pointee.ifa_name, ((String(utf8String: name)?.contains("tun")) != nil) { + // Get NSString from C String + if let value = temp_addr?.pointee.ifa_addr as? sockaddr_in { + address = String(utf8String: inet_ntoa(value.sin_addr)) + } + } + } + temp_addr = temp_addr?.pointee.ifa_next + } + } + freeifaddrs(interfaces) + return address + } +} + +enum TunnelType: String { + case wireguard, openvpn, empty +} + +extension String { + var toTunnelType: TunnelType { + switch self { + case "wireguard": return .wireguard + case "openvpn": return .openvpn + default: + return .empty + } + } } diff --git a/client/protocols/ios_vpnprotocol.h b/client/protocols/ios_vpnprotocol.h index d66a89a7..4cebe424 100644 --- a/client/protocols/ios_vpnprotocol.h +++ b/client/protocols/ios_vpnprotocol.h @@ -3,6 +3,7 @@ #include "vpnprotocol.h" #include "protocols/protocols_defs.h" +#include "json.h" using namespace amnezia; @@ -45,6 +46,12 @@ private: bool m_serviceConnected = false; bool m_checkingStatus = false; std::function m_logCallback; + + void setupWireguardProtocol(const QtJson::JsonObject& result); + void setupOpenVPNProtocol(const QtJson::JsonObject& result); + + void launchWireguardTunnel(const QtJson::JsonObject &result); + void launchOpenVPNTunnel(const QtJson::JsonObject &result); }; diff --git a/client/protocols/ios_vpnprotocol.mm b/client/protocols/ios_vpnprotocol.mm index 6e5246cb..38a75b23 100644 --- a/client/protocols/ios_vpnprotocol.mm +++ b/client/protocols/ios_vpnprotocol.mm @@ -10,8 +10,6 @@ #include -#include "json.h" - #include "ipaddressrange.h" #include "ios_vpnprotocol.h" #include "core/errorstrings.h" @@ -35,10 +33,9 @@ bool IOSVpnProtocol::initialize() { qDebug() << "Initializing Swift Controller"; - static bool creating = false; - // No nested creation! - Q_ASSERT(creating == false); - creating = true; + +// qDebug() << "config =>"; +// qDebug() << QJsonDocument(m_rawConfig).toJson(); if (!m_controller) { bool ok; @@ -49,142 +46,41 @@ bool IOSVpnProtocol::initialize() return false; } - QString vpnProto = result["protocol"].toString(); - qDebug() << "protocol: " << vpnProto; - qDebug() << "config data => "; - QtJson::JsonObject config = result["wireguard_config_data"].toMap(); - - QString privateKey = config["client_priv_key"].toString(); - QByteArray key = QByteArray::fromBase64(privateKey.toLocal8Bit()); - - qDebug() << " - " << "client_priv_key: " << config["client_priv_key"].toString(); - qDebug() << " - " << "client_pub_key: " << config["client_pub_key"].toString(); - qDebug() << " - " << "interface config: " << config["config"].toString(); - - QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast(); - QString dns = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast(); - QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast(); - QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast(); - QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast(); - QString allowedips = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast(); - QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast(); - QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast(); - qDebug() << " - " << "[Interface] address: " << addr; - qDebug() << " - " << "[Interface] dns: " << dns; - qDebug() << " - " << "[Interface] private key: " << privkey; - qDebug() << " - " << "[Peer] public key: " << pubkey; - qDebug() << " - " << "[Peer] preshared key: " << presharedkey; - qDebug() << " - " << "[Peer] allowed ips: " << allowedips; - qDebug() << " - " << "[Peer] endpoint: " << endpoint; - qDebug() << " - " << "[Peer] keepalive: " << keepalive; - - qDebug() << " - " << "hostName: " << config["hostName"].toString(); - qDebug() << " - " << "psk_key: " << config["psk_key"].toString(); - qDebug() << " - " << "server_pub_key: " << config["server_pub_key"].toString(); - - - - m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID - privateKey:key.toNSData() - deviceIpv4Address:addr.toNSString() - deviceIpv6Address:@"::/0" - closure:^(ConnectionState state, NSDate* date) { - qDebug() << "Creation completed with connection state:" << state; - creating = false; - - switch (state) { - case ConnectionStateError: { - [m_controller dealloc]; - m_controller = nullptr; - emit connectionStateChanged(VpnConnectionState::Error); - return; - } - case ConnectionStateConnected: { - Q_ASSERT(date); - QDateTime qtDate(QDateTime::fromNSDate(date)); - emit connectionStateChanged(VpnConnectionState::Connected); - return; - } - case ConnectionStateDisconnected: - // Just in case we are connecting, let's call disconnect. - [m_controller disconnect]; - emit connectionStateChanged(VpnConnectionState::Disconnected); - return; - } + QString protoName = result["protocol"].toString(); + qDebug() << "protocol: " << protoName; + + if (protoName == "wireguard") { + setupWireguardProtocol(result); + } else if (protoName == "openvpn") { + setupOpenVPNProtocol(result); + } else { + return false; } - callback:^(BOOL a_connected) { - qDebug() << "State changed: " << a_connected; - if (a_connected) { - emit connectionStateChanged(Connected); - return; - } -// emit connectionStateChanged(Disconnected); - }]; } return true; } + ErrorCode IOSVpnProtocol::start() { bool ok; QtJson::JsonObject result = QtJson::parse(QJsonDocument(m_rawConfig).toJson(), ok).toMap(); + qDebug() << "config: " << result; if(!ok) { qDebug() << QString("An error occurred during config parsing"); return InternalError; } QString protocol = result["protocol"].toString(); - QtJson::JsonObject config = result["wireguard_config_data"].toMap(); - QString clientPrivateKey = config["client_priv_key"].toString(); - QByteArray key = QByteArray::fromBase64(clientPrivateKey.toLocal8Bit()); - QString clientPubKey = config["client_pub_key"].toString(); - - QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast(); - QStringList dnsServersList = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast().split(", "); - QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast(); - QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast(); - QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast(); - QStringList allowedIPList = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast().split(", "); - QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast(); - QString serverAddr = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeFirst(); - QString port = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeLast(); - QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast(); - - QString hostname = config["hostName"].toString(); - QString pskKey = config["psk_key"].toString(); - QString serverPubKey = config["server_pub_key"].toString(); - - qDebug() << "IOSVPNProtocol starts for" << hostname; - qDebug() << "DNS:" << dnsServersList.takeFirst().toNSString(); - qDebug() << "serverPublicKey:" << serverPubKey.toNSString(); - qDebug() << "serverIpv4AddrIn:" << serverAddr.toNSString(); - qDebug() << "serverPort:" << (uint32_t)port.toInt(); - qDebug() << "allowed ip list" << allowedIPList; - - NSMutableArray* allowedIPAddressRangesNS = - [NSMutableArray arrayWithCapacity:allowedIPList.length()]; - for (const IPAddressRange item : allowedIPList) { - VPNIPAddressRange* range = - [[VPNIPAddressRange alloc] initWithAddress:item.ipAddress().toNSString() - networkPrefixLength:item.range() - isIpv6:item.type() == IPAddressRange::IPv6]; - [allowedIPAddressRangesNS addObject:[range autorelease]]; + if (protocol == "wireguard") { + launchWireguardTunnel(result); + } else if (protocol == "openvpn") { + launchOpenVPNTunnel(result); + } else { + return InternalError; } - [m_controller connectWithDnsServer:dnsServersList.takeFirst().toNSString() - serverIpv6Gateway:@"FE80::1" - serverPublicKey:serverPubKey.toNSString() - presharedKey:pskKey.toNSString() - serverIpv4AddrIn:serverAddr.toNSString() - serverPort:port.toInt() - allowedIPAddressRanges:allowedIPAddressRangesNS - ipv6Enabled:NO - reason:0 - failureCallback:^() { - qDebug() << "IOSVPNProtocol - connection failed"; - emit connectionStateChanged(Disconnected); - }]; return NoError; } @@ -296,3 +192,197 @@ void IOSVpnProtocol::cleanupBackendLogs() file.remove(); } +void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result) +{ + static bool creating = false; + // No nested creation! + Q_ASSERT(creating == false); + creating = true; + + QtJson::JsonObject config = result["wireguard_config_data"].toMap(); + + QString privateKey = config["client_priv_key"].toString(); + QByteArray key = QByteArray::fromBase64(privateKey.toLocal8Bit()); + + qDebug() << " - " << "client_priv_key: " << config["client_priv_key"].toString(); + qDebug() << " - " << "client_pub_key: " << config["client_pub_key"].toString(); + qDebug() << " - " << "interface config: " << config["config"].toString(); + + QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast(); + QString dns = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast(); + QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast(); + QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast(); + QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast(); + QString allowedips = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast(); + QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast(); + QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast(); + qDebug() << " - " << "[Interface] address: " << addr; + qDebug() << " - " << "[Interface] dns: " << dns; + qDebug() << " - " << "[Interface] private key: " << privkey; + qDebug() << " - " << "[Peer] public key: " << pubkey; + qDebug() << " - " << "[Peer] preshared key: " << presharedkey; + qDebug() << " - " << "[Peer] allowed ips: " << allowedips; + qDebug() << " - " << "[Peer] endpoint: " << endpoint; + qDebug() << " - " << "[Peer] keepalive: " << keepalive; + + qDebug() << " - " << "hostName: " << config["hostName"].toString(); + qDebug() << " - " << "psk_key: " << config["psk_key"].toString(); + qDebug() << " - " << "server_pub_key: " << config["server_pub_key"].toString(); + + + + m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID + privateKey:key.toNSData() + deviceIpv4Address:addr.toNSString() + deviceIpv6Address:@"::/0" + closure:^(ConnectionState state, NSDate* date) { + qDebug() << "Creation completed with connection state:" << state; + creating = false; + + switch (state) { + case ConnectionStateError: { + [m_controller dealloc]; + m_controller = nullptr; + emit connectionStateChanged(VpnConnectionState::Error); + return; + } + case ConnectionStateConnected: { + Q_ASSERT(date); + QDateTime qtDate(QDateTime::fromNSDate(date)); + emit connectionStateChanged(VpnConnectionState::Connected); + return; + } + case ConnectionStateDisconnected: + // Just in case we are connecting, let's call disconnect. + [m_controller disconnect]; + emit connectionStateChanged(VpnConnectionState::Disconnected); + return; + } + } + callback:^(BOOL a_connected) { + qDebug() << "State changed: " << a_connected; + if (a_connected) { + emit connectionStateChanged(Connected); + return; + } + emit connectionStateChanged(Disconnected); + }]; +} + +void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result) +{ + static bool creating = false; + // No nested creation! + Q_ASSERT(creating == false); + creating = true; + + QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap(); + QString ovpnConfig = ovpn["config"].toString(); +// qDebug() << ovpn; + + m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID + config:ovpnConfig.toNSString() + closure:^(ConnectionState state, NSDate* date) { + qDebug() << "OVPN Creation completed with connection state:" << state; + creating = false; + + switch (state) { + case ConnectionStateError: { + [m_controller dealloc]; + m_controller = nullptr; + emit connectionStateChanged(VpnConnectionState::Error); + return; + } + case ConnectionStateConnected: { + Q_ASSERT(date); + QDateTime qtDate(QDateTime::fromNSDate(date)); + emit connectionStateChanged(VpnConnectionState::Connected); + return; + } + case ConnectionStateDisconnected: + // Just in case we are connecting, let's call disconnect. + [m_controller disconnect]; + emit connectionStateChanged(VpnConnectionState::Disconnected); + return; + } + } + callback:^(BOOL a_connected) { + qDebug() << "OVPN State changed: " << a_connected; + if (a_connected) { + emit connectionStateChanged(Connected); + return; + } + emit connectionStateChanged(Disconnected); + }]; +} + +void IOSVpnProtocol::launchWireguardTunnel(const QtJson::JsonObject &result) +{ + QtJson::JsonObject config = result["wireguard_config_data"].toMap(); + + QString clientPrivateKey = config["client_priv_key"].toString(); + QByteArray key = QByteArray::fromBase64(clientPrivateKey.toLocal8Bit()); + QString clientPubKey = config["client_pub_key"].toString(); + + QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast(); + QStringList dnsServersList = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast().split(", "); + QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast(); + QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast(); + QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast(); + QStringList allowedIPList = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast().split(", "); + QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast(); + QString serverAddr = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeFirst(); + QString port = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeLast(); + QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast(); + + QString hostname = config["hostName"].toString(); + QString pskKey = config["psk_key"].toString(); + QString serverPubKey = config["server_pub_key"].toString(); + + qDebug() << "IOSVPNProtocol starts for" << hostname; + qDebug() << "DNS:" << dnsServersList.takeFirst().toNSString(); + qDebug() << "serverPublicKey:" << serverPubKey.toNSString(); + qDebug() << "serverIpv4AddrIn:" << serverAddr.toNSString(); + qDebug() << "serverPort:" << (uint32_t)port.toInt(); + qDebug() << "allowed ip list" << allowedIPList; + + NSMutableArray* allowedIPAddressRangesNS = + [NSMutableArray arrayWithCapacity:allowedIPList.length()]; + for (const IPAddressRange item : allowedIPList) { + VPNIPAddressRange* range = + [[VPNIPAddressRange alloc] initWithAddress:item.ipAddress().toNSString() + networkPrefixLength:item.range() + isIpv6:item.type() == IPAddressRange::IPv6]; + [allowedIPAddressRangesNS addObject:[range autorelease]]; + } + + [m_controller connectWithDnsServer:dnsServersList.takeFirst().toNSString() + serverIpv6Gateway:@"FE80::1" + serverPublicKey:serverPubKey.toNSString() + presharedKey:pskKey.toNSString() + serverIpv4AddrIn:serverAddr.toNSString() + serverPort:port.toInt() + allowedIPAddressRanges:allowedIPAddressRangesNS + ipv6Enabled:NO + reason:0 + failureCallback:^() { + qDebug() << "Wireguard Protocol - connection failed"; + emit connectionStateChanged(Disconnected); + }]; +} + +void IOSVpnProtocol::launchOpenVPNTunnel(const QtJson::JsonObject &result) +{ + QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap(); + QString ovpnConfig = ovpn["config"].toString(); + + [m_controller connectWithOvpnConfig:ovpnConfig.toNSString() + failureCallback:^{ + qDebug() << "IOSVPNProtocol - connection failed"; + emit connectionStateChanged(Disconnected); + }]; +} + + + + diff --git a/client/scripts/commons.sh b/client/scripts/commons.sh index 13ff5703..7abe5aa1 100644 --- a/client/scripts/commons.sh +++ b/client/scripts/commons.sh @@ -39,6 +39,26 @@ error() { printv '' R "$1" } +XCODEBUILD="/usr/bin/xcodebuild" +WORKINGDIR=`pwd` + +compile_openvpn_adapter() { + cd 3rd/OpenVPNAdapter + + $XCODEBUILD -scheme OpenVPNAdapter -configuration Debug -xcconfig Configuration/amnezia.xcconfig -sdk iphoneos -destination 'generic/platform=iOS' -project OpenVPNAdapter.xcodeproj + + cd ../../ +} + +prepare_to_build_vpn() { + cat $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/Project.xcconfig > $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig + cat << EOF >> $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig + PROJECT_TEMP_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/OpenVPNAdapter.build + CONFIGURATION_BUILD_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Debug-iphoneos + BUILT_PRODUCTS_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Debug-iphoneos +EOF +} + die() { if [[ "$1" ]]; then error "$1" diff --git a/client/scripts/ios_compile.sh b/client/scripts/ios_compile.sh index fcce7649..96609560 100755 --- a/client/scripts/ios_compile.sh +++ b/client/scripts/ios_compile.sh @@ -126,7 +126,7 @@ printn Y "Retrieve the wireguard-go version... " print G "done." printn Y "Cleaning the existing project... " -rm -rf mozillavpn.xcodeproj/ || die "Failed to remove things" +rm -rf AmneziaVPN.xcodeproj/ || die "Failed to remove things" print G "done." #print Y "Importing translation files..." @@ -205,6 +205,16 @@ else print G none fi +if [ "$OS" = "ios" ]; then + print Y "Prepare to build OpenVPNAdapter..." + prepare_to_build_vpn + print Y "Building OpenVPNAdapter..." + compile_openvpn_adapter +else + print Y "No OpenVPNAdapter will be built" + +fi + print Y "Creating the xcode project via qmake..." $QMAKE \ VERSION=$SHORTVERSION \ diff --git a/client/scripts/xcode_patcher.rb b/client/scripts/xcode_patcher.rb index d950c886..56277cb3 100644 --- a/client/scripts/xcode_patcher.rb +++ b/client/scripts/xcode_patcher.rb @@ -61,7 +61,8 @@ class XCodeprojPatcher config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= 'macos/app/WireGuard-Bridging-Header.h' config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [ "$(inherited)", - "$(PROJECT_DIR)/3rd" + "$(PROJECT_DIR)/3rd", + "$(PROJECT_DIR)/3rd/OpenVPNAdapter/build/Debug-iphoneos" ] # Versions and names @@ -251,6 +252,11 @@ class XCodeprojPatcher config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= 'macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h' config.build_settings['SWIFT_PRECOMPILE_BRIDGING_HEADER'] = 'NO' config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES' + config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [ + "$(inherited)", + "$(PROJECT_DIR)/3rd", + "$(PROJECT_DIR)/3rd/OpenVPNAdapter/build/Debug-iphoneos" + ] # Versions and names config.build_settings['MARKETING_VERSION'] ||= shortVersion @@ -350,6 +356,18 @@ class XCodeprojPatcher framework_ref = frameworks_group.new_file('NetworkExtension.framework') frameworks_build_phase.add_file_reference(framework_ref) + + framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/LZ4.framework') + frameworks_build_phase.add_file_reference(framework_ref) + + framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/mbedTLS.framework') + frameworks_build_phase.add_file_reference(framework_ref) + + framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNClient.framework') + frameworks_build_phase.add_file_reference(framework_ref) + + framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNAdapter.framework') + frameworks_build_phase.add_file_reference(framework_ref) # This fails: @target_main.add_dependency @target_extension container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy) diff --git a/client/xcode.xconfig b/client/xcode.xconfig index 01eb90fe..b93841e8 100644 --- a/client/xcode.xconfig +++ b/client/xcode.xconfig @@ -1,4 +1,4 @@ -DEVELOPMENT_TEAM = X7UJ388FXK +DEVELOPMENT_TEAM = 7VAGZXD78P GROUP_ID_IOS = group.ru.kotit.AmneziaVPN.udev APP_ID_IOS = ru.kotit.AmneziaVPN