diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2024-06-24 13:21:40 +0200 |
|---|---|---|
| committer | Emīls <emils@mullvad.net> | 2024-07-17 11:48:13 +0200 |
| commit | 2df280fbf02fa1b39efffb0b27b297d39d6369c0 (patch) | |
| tree | 1b6a657bb8c594e82a50bd4dfcbfb85d34395fa1 /ios/MullvadRustRuntime | |
| parent | b6fe08388dcbfbe1fb54a1c89322c329be2f54f9 (diff) | |
| download | mullvadvpn-2df280fbf02fa1b39efffb0b27b297d39d6369c0.tar.xz mullvadvpn-2df280fbf02fa1b39efffb0b27b297d39d6369c0.zip | |
Add a Rust FFI, Disable sandboxing for scripts
Diffstat (limited to 'ios/MullvadRustRuntime')
| -rw-r--r-- | ios/MullvadRustRuntime/MullvadRustRuntime.h | 10 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift | 112 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift | 137 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift | 78 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/ShadowSocksProxy.swift | 91 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/UDPOverTCPObfuscator.swift | 87 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/include/mullvad_rust_runtime.h | 137 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/module.private.modulemap | 5 |
8 files changed, 657 insertions, 0 deletions
diff --git a/ios/MullvadRustRuntime/MullvadRustRuntime.h b/ios/MullvadRustRuntime/MullvadRustRuntime.h new file mode 100644 index 0000000000..a490829628 --- /dev/null +++ b/ios/MullvadRustRuntime/MullvadRustRuntime.h @@ -0,0 +1,10 @@ +// +// MullvadRustRuntime.h +// MullvadRustRuntime +// +// Created by Marco Nikic on 2024-06-20. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "mullvad_rust_runtime.h" diff --git a/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift b/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift new file mode 100644 index 0000000000..4c1b3b1607 --- /dev/null +++ b/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift @@ -0,0 +1,112 @@ +// +// PacketTunnelProvider+TCPConnection.swift +// PacketTunnel +// +// Created by Marco Nikic on 2024-02-15. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadRustRuntimeProxy +import MullvadTypes +import NetworkExtension +import WireGuardKitTypes + +/// Writes data to the in-tunnel TCP connection +/// +/// This FFI function is called by Rust whenever there is data to be written to the in-tunnel TCP connection when exchanging +/// quantum-resistant pre shared keys. +/// +/// Whenever the flow control is given back from the connection, acknowledge that data was written using `rawWriteAcknowledgement`. +/// - Parameters: +/// - rawConnection: A raw pointer to the in-tunnel TCP connection +/// - rawData: A raw pointer to the data to write in the connection +/// - dataLength: The length of data to write in the connection +/// - rawWriteAcknowledgement: An opaque pointer needed for write acknowledgement +@_cdecl("swift_nw_tcp_connection_send") +func tcpConnectionSend( + rawConnection: UnsafeMutableRawPointer?, + rawData: UnsafeMutableRawPointer, + dataLength: UInt, + rawWriteAcknowledgement: UnsafeMutableRawPointer? +) { + guard let rawConnection, let rawWriteAcknowledgement else { + handle_sent(0, rawWriteAcknowledgement) + return + } + let tcpConnection = Unmanaged<NWTCPConnection>.fromOpaque(rawConnection).takeUnretainedValue() + let data = Data(bytes: rawData, count: Int(dataLength)) + + // The guarantee that all writes are sequential is done by virtue of not returning the execution context + // to Rust before this closure is done executing. + tcpConnection.write(data, completionHandler: { maybeError in + if maybeError != nil { + handle_sent(0, rawWriteAcknowledgement) + } else { + handle_sent(dataLength, rawWriteAcknowledgement) + } + }) +} + +/// Reads data to the in-tunnel TCP connection +/// +/// This FFI function is called by Rust whenever there is data to be read from the in-tunnel TCP connection when exchanging +/// quantum-resistant pre shared keys. +/// +/// Whenever the flow control is given back from the connection, acknowledge that data was read using `rawReadAcknowledgement`. +/// - Parameters: +/// - rawConnection: A raw pointer to the in-tunnel TCP connection +/// - rawReadAcknowledgement: An opaque pointer needed for read acknowledgement +@_cdecl("swift_nw_tcp_connection_read") +func tcpConnectionReceive( + rawConnection: UnsafeMutableRawPointer?, + rawReadAcknowledgement: UnsafeMutableRawPointer? +) { + guard let rawConnection, let rawReadAcknowledgement else { + handle_recv(nil, 0, rawReadAcknowledgement) + return + } + let tcpConnection = Unmanaged<NWTCPConnection>.fromOpaque(rawConnection).takeUnretainedValue() + tcpConnection.readMinimumLength(0, maximumLength: Int(UInt16.max)) { data, maybeError in + if let data { + if maybeError != nil { + handle_recv(nil, 0, rawReadAcknowledgement) + } else { + handle_recv(data.map { $0 }, UInt(data.count), rawReadAcknowledgement) + } + } + } +} + +/// End sequence of a quantum-secure pre shared key exchange. +/// +/// This FFI function is called by Rust when the quantum-secure pre shared key exchange has either failed, or succeeded. +/// When both the `rawPresharedKey` and the `rawEphemeralKey` are raw pointers to 32 bytes data arrays, +/// the quantum-secure key exchange is considered successful. In any other case, the exchange is considered failed. +/// +/// - Parameters: +/// - rawPacketTunnel: A raw pointer to the running instance of `NEPacketTunnelProvider` +/// - rawPresharedKey: A raw pointer to the quantum-secure pre shared key +/// - rawEphemeralKey: A raw pointer to the ephemeral private key of the device +@_cdecl("swift_post_quantum_key_ready") +func receivePostQuantumKey( + rawPostQuantumKeyReceiver: UnsafeMutableRawPointer?, + rawPresharedKey: UnsafeMutableRawPointer?, + rawEphemeralKey: UnsafeMutableRawPointer? +) { + guard let rawPostQuantumKeyReceiver else { return } + let postQuantumKeyReceiver = Unmanaged<PostQuantumKeyReceiver>.fromOpaque(rawPostQuantumKeyReceiver) + .takeUnretainedValue() + + guard + let rawPresharedKey, + let rawEphemeralKey, + let ephemeralKey = PrivateKey(rawValue: Data(bytes: rawEphemeralKey, count: 32)), + let key = PreSharedKey(rawValue: Data(bytes: rawPresharedKey, count: 32)) + else { + postQuantumKeyReceiver.keyExchangeFailed() + return + } + + postQuantumKeyReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) +} diff --git a/ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift b/ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift new file mode 100644 index 0000000000..8028c1ba3e --- /dev/null +++ b/ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift @@ -0,0 +1,137 @@ +// +// PostQuantumKeyExchangeActor.swift +// PacketTunnel +// +// Created by Marco Nikic on 2024-04-12. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadRustRuntimeProxy +import MullvadTypes +import NetworkExtension +import WireGuardKitTypes + +public class PostQuantumKeyExchangeActor { + struct Negotiation { + var negotiator: PostQuantumKeyNegotiating + var inTunnelTCPConnection: NWTCPConnection + var tcpConnectionObserver: NSKeyValueObservation + + func cancel() { + negotiator.cancelKeyNegotiation() + tcpConnectionObserver.invalidate() + inTunnelTCPConnection.cancel() + } + } + + unowned let packetTunnel: any TunnelProvider + internal var negotiation: Negotiation? + private var timer: DispatchSourceTimer? + private var keyExchangeRetriesIterator: AnyIterator<Duration>! + private let iteratorProvider: () -> AnyIterator<Duration> + private let negotiationProvider: PostQuantumKeyNegotiating.Type + + // Callback in the event of the negotiation failing on startup + var onFailure: () -> Void + + public init( + packetTunnel: any TunnelProvider, + onFailure: @escaping (() -> Void), + negotiationProvider: PostQuantumKeyNegotiating.Type = PostQuantumKeyNegotiator.self, + iteratorProvider: @escaping () -> AnyIterator<Duration> + ) { + self.packetTunnel = packetTunnel + self.onFailure = onFailure + self.negotiationProvider = negotiationProvider + self.iteratorProvider = iteratorProvider + self.keyExchangeRetriesIterator = iteratorProvider() + } + + private func createTCPConnection(_ gatewayEndpoint: NWHostEndpoint) -> NWTCPConnection { + self.packetTunnel.createTCPConnectionThroughTunnel( + to: gatewayEndpoint, + enableTLS: false, + tlsParameters: nil, + delegate: nil + ) + } + + /// Starts a new key exchange. + /// + /// Any ongoing key negotiation is stopped before starting a new one. + /// An exponential backoff timer is used to stop the exchange if it takes too long, + /// or if the TCP connection takes too long to become ready. + /// It is reset after every successful key exchange. + /// + /// - Parameter privateKey: The device's current private key + public func startNegotiation(with privateKey: PrivateKey) { + endCurrentNegotiation() + let negotiator = negotiationProvider.init() + + let gatewayAddress = "10.64.0.1" + let IPv4Gateway = IPv4Address(gatewayAddress)! + let endpoint = NWHostEndpoint(hostname: gatewayAddress, port: "\(CONFIG_SERVICE_PORT)") + let inTunnelTCPConnection = createTCPConnection(endpoint) + + // This will become the new private key of the device + let ephemeralSharedKey = PrivateKey() + + let tcpConnectionTimeout = keyExchangeRetriesIterator.next() ?? .seconds(10) + // If the connection never becomes viable, force a reconnection after 10 seconds + scheduleInTunnelConnectionTimeout(startTime: .now() + tcpConnectionTimeout) + + let tcpConnectionObserver = inTunnelTCPConnection.observe(\.isViable, options: [ + .initial, + .new, + ]) { [weak self] observedConnection, _ in + guard let self, observedConnection.isViable else { return } + self.negotiation?.tcpConnectionObserver.invalidate() + self.timer?.cancel() + + if !negotiator.startNegotiation( + gatewayIP: IPv4Gateway, + devicePublicKey: privateKey.publicKey, + presharedKey: ephemeralSharedKey, + postQuantumKeyReceiver: packetTunnel, + tcpConnection: inTunnelTCPConnection, + postQuantumKeyExchangeTimeout: tcpConnectionTimeout + ) { + self.negotiation = nil + self.onFailure() + } + } + negotiation = Negotiation( + negotiator: negotiator, + inTunnelTCPConnection: inTunnelTCPConnection, + tcpConnectionObserver: tcpConnectionObserver + ) + } + + /// Cancels the ongoing key exchange. + public func endCurrentNegotiation() { + negotiation?.cancel() + negotiation = nil + } + + /// Resets the exponential timeout for successful key exchanges, and ends the current key exchange. + public func reset() { + keyExchangeRetriesIterator = iteratorProvider() + endCurrentNegotiation() + } + + private func scheduleInTunnelConnectionTimeout(startTime: DispatchWallTime) { + let newTimer = DispatchSource.makeTimerSource() + + newTimer.setEventHandler { [weak self] in + self?.onFailure() + self?.timer?.cancel() + } + + newTimer.schedule(wallDeadline: startTime) + newTimer.activate() + + timer?.cancel() + timer = newTimer + } +} diff --git a/ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift b/ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift new file mode 100644 index 0000000000..c653fc8983 --- /dev/null +++ b/ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift @@ -0,0 +1,78 @@ +// +// PostQuantumKeyNegotiator.swift +// PacketTunnel +// +// Created by Marco Nikic on 2024-02-16. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadTypes +import NetworkExtension +import WireGuardKitTypes + +// swiftlint:disable function_parameter_count +public protocol PostQuantumKeyNegotiating { + func startNegotiation( + gatewayIP: IPv4Address, + devicePublicKey: PublicKey, + presharedKey: PrivateKey, + postQuantumKeyReceiver: any TunnelProvider, + tcpConnection: NWTCPConnection, + postQuantumKeyExchangeTimeout: Duration + ) -> Bool + + func cancelKeyNegotiation() + + init() +} + +/** + Attempt to start the asynchronous process of key negotiation. Returns true if successfully started, false if failed. + */ +public class PostQuantumKeyNegotiator: PostQuantumKeyNegotiating { + required public init() {} + + var cancelToken: PostQuantumCancelToken? + + public func startNegotiation( + gatewayIP: IPv4Address, + devicePublicKey: PublicKey, + presharedKey: PrivateKey, + postQuantumKeyReceiver: any TunnelProvider, + tcpConnection: NWTCPConnection, + postQuantumKeyExchangeTimeout: Duration + ) -> Bool { + // swiftlint:disable:next force_cast + let postQuantumKeyReceiver = Unmanaged.passUnretained(postQuantumKeyReceiver as! PostQuantumKeyReceiver) + .toOpaque() + let opaqueConnection = Unmanaged.passUnretained(tcpConnection).toOpaque() + var cancelToken = PostQuantumCancelToken() + + let result = negotiate_post_quantum_key( + devicePublicKey.rawValue.map { $0 }, + presharedKey.rawValue.map { $0 }, + postQuantumKeyReceiver, + opaqueConnection, + &cancelToken, + UInt64(postQuantumKeyExchangeTimeout.timeInterval) + ) + guard result == 0 else { + return false + } + self.cancelToken = cancelToken + return true + } + + public func cancelKeyNegotiation() { + guard var cancelToken else { return } + cancel_post_quantum_key_exchange(&cancelToken) + } + + deinit { + guard var cancelToken else { return } + drop_post_quantum_key_exchange_token(&cancelToken) + } +} + +// swiftlint:enable function_parameter_count diff --git a/ios/MullvadRustRuntime/ShadowSocksProxy.swift b/ios/MullvadRustRuntime/ShadowSocksProxy.swift new file mode 100644 index 0000000000..cd83f2129a --- /dev/null +++ b/ios/MullvadRustRuntime/ShadowSocksProxy.swift @@ -0,0 +1,91 @@ +// +// ShadowsocksProxy.swift +// MullvadREST +// +// Created by Emils on 19/04/2023. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadRustRuntimeProxy +import Network + +/// A Swift wrapper around a Rust implementation of Shadowsocks proxy instance +public class ShadowsocksProxy { + private var proxyConfig: ProxyHandle + private let forwardAddress: IPAddress + private let forwardPort: UInt16 + private let bridgeAddress: IPAddress + private let bridgePort: UInt16 + private let password: String + private let cipher: String + private var didStart = false + private let stateLock = NSLock() + + public init( + forwardAddress: IPAddress, + forwardPort: UInt16, + bridgeAddress: IPAddress, + bridgePort: UInt16, + password: String, + cipher: String + ) { + proxyConfig = ProxyHandle(context: nil, port: 0) + self.forwardAddress = forwardAddress + self.forwardPort = forwardPort + self.bridgeAddress = bridgeAddress + self.bridgePort = bridgePort + self.password = password + self.cipher = cipher + } + + /// The local port for the shadow socks proxy + /// + /// - Returns: The local port for the shadow socks proxy when it has started, 0 otherwise. + public func localPort() -> UInt16 { + stateLock.lock() + defer { stateLock.unlock() } + return proxyConfig.port + } + + deinit { + stop() + } + + /// Starts the socks proxy + public func start() { + stateLock.lock() + defer { stateLock.unlock() } + guard didStart == false else { return } + didStart = true + + // Get the raw bytes access to `proxyConfig` + _ = withUnsafeMutablePointer(to: &proxyConfig) { config in + start_shadowsocks_proxy( + forwardAddress.rawValue.map { $0 }, + UInt(forwardAddress.rawValue.count), + forwardPort, + bridgeAddress.rawValue.map { $0 }, + UInt(bridgeAddress.rawValue.count), + bridgePort, + password, + UInt(password.count), + cipher, + UInt(cipher.count), + config + ) + } + } + + /// Stops the socks proxy + public func stop() { + stateLock.lock() + defer { stateLock.unlock() } + guard didStart == true else { return } + didStart = false + + _ = withUnsafeMutablePointer(to: &proxyConfig) { config in + stop_shadowsocks_proxy(config) + } + } +} diff --git a/ios/MullvadRustRuntime/UDPOverTCPObfuscator.swift b/ios/MullvadRustRuntime/UDPOverTCPObfuscator.swift new file mode 100644 index 0000000000..8d5d874c84 --- /dev/null +++ b/ios/MullvadRustRuntime/UDPOverTCPObfuscator.swift @@ -0,0 +1,87 @@ +// +// TunnelObfuscator.swift +// TunnelObfuscation +// +// Created by pronebird on 19/06/2023. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadRustRuntimeProxy +import MullvadTypes +import Network + +public protocol TunnelObfuscation { + init(remoteAddress: IPAddress, tcpPort: UInt16) + func start() + func stop() + var localUdpPort: UInt16 { get } + var remotePort: UInt16 { get } + + var transportLayer: TransportLayer { get } +} + +/// Class that implements UDP over TCP obfuscation by accepting traffic on a local UDP port and proxying it over TCP to the remote endpoint. +public final class UDPOverTCPObfuscator: TunnelObfuscation { + private let stateLock = NSLock() + private let remoteAddress: IPAddress + internal let tcpPort: UInt16 + + private var proxyHandle = ProxyHandle(context: nil, port: 0) + private var isStarted = false + + /// Returns local UDP port used by proxy and bound to 127.0.0.1 (IPv4). + /// The returned value can be zero if obfuscator hasn't started yet. + public var localUdpPort: UInt16 { + return stateLock.withLock { proxyHandle.port } + } + + public var remotePort: UInt16 { tcpPort } + + public var transportLayer: TransportLayer { .tcp } + + /// Initialize tunnel obfuscator with remote server address and TCP port where udp2tcp is running. + public init(remoteAddress: IPAddress, tcpPort: UInt16) { + self.remoteAddress = remoteAddress + self.tcpPort = tcpPort + } + + deinit { + stop() + } + + public func start() { + stateLock.withLock { + guard !isStarted else { return } + + let result = withUnsafeMutablePointer(to: &proxyHandle) { proxyHandlePointer in + let addressData = remoteAddress.rawValue + + return start_tunnel_obfuscator_proxy( + addressData.map { $0 }, + UInt(addressData.count), + tcpPort, + proxyHandlePointer + ) + } + + assert(result == 0) + + isStarted = true + } + } + + public func stop() { + stateLock.withLock { + guard isStarted else { return } + + let result = withUnsafeMutablePointer(to: &proxyHandle) { + stop_tunnel_obfuscator_proxy($0) + } + + assert(result == 0) + + isStarted = false + } + } +} diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h new file mode 100644 index 0000000000..9b5c8bd4c1 --- /dev/null +++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h @@ -0,0 +1,137 @@ +// This file is generated automatically. To update it forcefully, run `cargo run -p mullvad-ios --target aarch64-apple-ios`. + +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +typedef struct PostQuantumCancelToken { + void *context; +} PostQuantumCancelToken; + +typedef struct ProxyHandle { + void *context; + uint16_t port; +} ProxyHandle; + +extern const uint16_t CONFIG_SERVICE_PORT; + +/** + * Called by the Swift side to signal that the quantum-secure key exchange should be cancelled. + * After this call, the cancel token is no longer valid. + * + * # Safety + * `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the + * `PacketTunnelProvider`. + */ +void cancel_post_quantum_key_exchange(const struct PostQuantumCancelToken *sender); + +/** + * Called by the Swift side to signal that the Rust `PostQuantumCancelToken` can be safely dropped + * from memory. + * + * # Safety + * `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the + * `PacketTunnelProvider`. + */ +void drop_post_quantum_key_exchange_token(const struct PostQuantumCancelToken *sender); + +/** + * Called by Swift whenever data has been written to the in-tunnel TCP connection when exchanging + * quantum-resistant pre shared keys. + * + * If `bytes_sent` is 0, this indicates that the connection was closed or that an error occurred. + * + * # Safety + * `sender` must be pointing to a valid instance of a `write_tx` created by the `IosTcpProvider` + * Callback to call when the TCP connection has written data. + */ +void handle_sent(uintptr_t bytes_sent, const void *sender); + +/** + * Called by Swift whenever data has been read from the in-tunnel TCP connection when exchanging + * quantum-resistant pre shared keys. + * + * If `data` is null or empty, this indicates that the connection was closed or that an error + * occurred. An empty buffer is sent to the underlying reader to signal EOF. + * + * # Safety + * `sender` must be pointing to a valid instance of a `read_tx` created by the `IosTcpProvider` + * + * Callback to call when the TCP connection has received data. + */ +void handle_recv(const uint8_t *data, uintptr_t data_len, const void *sender); + +/** + * Entry point for exchanging post quantum keys on iOS. + * The TCP connection must be created to go through the tunnel. + * # Safety + * `public_key` and `ephemeral_key` must be valid respective `PublicKey` and `PrivateKey` types. + * They will not be valid after this function is called, and thus must be copied here. + * `packet_tunnel` and `tcp_connection` must be valid pointers to a packet tunnel and a TCP + * connection instances. + * `cancel_token` should be owned by the caller of this function. + */ +int32_t negotiate_post_quantum_key(const uint8_t *public_key, + const uint8_t *ephemeral_key, + const void *packet_tunnel, + const void *tcp_connection, + struct PostQuantumCancelToken *cancel_token, + uint64_t post_quantum_key_exchange_timeout); + +/** + * Called when there is data to send on the TCP connection. + * The TCP connection must write data on the wire, then call the `handle_sent` function. + */ +extern void swift_nw_tcp_connection_send(const void *connection, + const void *data, + uintptr_t data_len, + const void *sender); + +/** + * Called when there is data to read on the TCP connection. + * The TCP connection must read data from the wire, then call the `handle_read` function. + */ +extern void swift_nw_tcp_connection_read(const void *connection, const void *sender); + +/** + * Called when the preshared post quantum key is ready. + * `raw_preshared_key` might be NULL if the key negotiation failed. + */ +extern void swift_post_quantum_key_ready(const void *raw_packet_tunnel, + const uint8_t *raw_preshared_key, + const uint8_t *raw_ephemeral_private_key); + +/** + * # Safety + * `addr`, `password`, `cipher` must be valid for the lifetime of this function call and they must + * be backed by the amount of bytes as stored in the respective `*_len` parameters. + * + * `proxy_config` must be pointing to a valid memory region for the size of a `ProxyHandle` + * instance. + */ +int32_t start_shadowsocks_proxy(const uint8_t *forward_address, + uintptr_t forward_address_len, + uint16_t forward_port, + const uint8_t *addr, + uintptr_t addr_len, + uint16_t port, + const uint8_t *password, + uintptr_t password_len, + const uint8_t *cipher, + uintptr_t cipher_len, + struct ProxyHandle *proxy_config); + +/** + * # Safety + * `proxy_config` must be pointing to a valid instance of a `ProxyInstance`, as instantiated by + * `start_shadowsocks_proxy`. + */ +int32_t stop_shadowsocks_proxy(struct ProxyHandle *proxy_config); + +int32_t start_tunnel_obfuscator_proxy(const uint8_t *peer_address, + uintptr_t peer_address_len, + uint16_t peer_port, + struct ProxyHandle *proxy_handle); + +int32_t stop_tunnel_obfuscator_proxy(struct ProxyHandle *proxy_handle); diff --git a/ios/MullvadRustRuntime/module.private.modulemap b/ios/MullvadRustRuntime/module.private.modulemap new file mode 100644 index 0000000000..5115e403a2 --- /dev/null +++ b/ios/MullvadRustRuntime/module.private.modulemap @@ -0,0 +1,5 @@ +framework module MullvadRustRuntimeProxy { + header "mullvad_rust_runtime.h" + link "libmullvad_ios" + export * +} |
