mirror of
https://github.com/aphrody-labs/mullvadvpn-app.git
synced 2026-10-13 22:10:39 +00:00
Add a Rust FFI, Disable sandboxing for scripts
This commit is contained in:
1 parent
b6fe08388d
commit
2df280fbf0
58 files changed
+704
-1421
No files matched your search
Generated
+17
-23
@@ -2243,6 +2243,23 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mullvad-ios"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"libc",
|
||||
"log",
|
||||
"oslog",
|
||||
"shadowsocks-service",
|
||||
"talpid-tunnel-config-client",
|
||||
"talpid-types",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tower",
|
||||
"tunnel-obfuscation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mullvad-jni"
|
||||
version = "0.0.0"
|
||||
@@ -3614,17 +3631,6 @@ dependencies = [
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shadowsocks-proxy"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"log",
|
||||
"oslog",
|
||||
"shadowsocks-service",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shadowsocks-service"
|
||||
version = "1.18.3"
|
||||
@@ -4051,7 +4057,6 @@ dependencies = [
|
||||
name = "talpid-tunnel-config-client"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"classic-mceliece-rust",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -4492,17 +4497,6 @@ dependencies = [
|
||||
"udp-over-tcp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tunnel-obfuscator-proxy"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"log",
|
||||
"oslog",
|
||||
"tokio",
|
||||
"tunnel-obfuscation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
|
||||
+3
-4
@@ -9,13 +9,12 @@ rust-version = "1.77.0"
|
||||
resolver = "2"
|
||||
members = [
|
||||
"android/translations-converter",
|
||||
"ios/MullvadREST/Transport/Shadowsocks/shadowsocks-proxy",
|
||||
"ios/TunnelObfuscation/tunnel-obfuscator-proxy",
|
||||
"mullvad-api",
|
||||
"mullvad-cli",
|
||||
"mullvad-daemon",
|
||||
"mullvad-exclude",
|
||||
"mullvad-fs",
|
||||
"mullvad-ios",
|
||||
"mullvad-jni",
|
||||
"mullvad-management-interface",
|
||||
"mullvad-nsis",
|
||||
@@ -39,7 +38,7 @@ members = [
|
||||
"talpid-windows",
|
||||
"talpid-wireguard",
|
||||
"tunnel-obfuscation",
|
||||
"wireguard-go-rs"
|
||||
"wireguard-go-rs",
|
||||
]
|
||||
|
||||
# Keep all lints in sync with `test/Cargo.toml`
|
||||
@@ -81,7 +80,7 @@ shadowsocks-service = { version = "1.16" }
|
||||
|
||||
windows-sys = "0.52.0"
|
||||
|
||||
chrono = { version = "0.4.26", default-features = false}
|
||||
chrono = { version = "0.4.26", default-features = false }
|
||||
clap = { version = "4.4.18", features = ["cargo", "derive"] }
|
||||
once_cell = "1.13"
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// MullvadPostQuantum.h
|
||||
// MullvadPostQuantum
|
||||
//
|
||||
// Created by Marco Nikic on 2024-02-27.
|
||||
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "talpid_tunnel_config_client.h"
|
||||
@@ -1,5 +0,0 @@
|
||||
framework module TalpidTunnelConfigClientProxy {
|
||||
header "talpid_tunnel_config_client.h"
|
||||
link "libtalpid_tunnel_config_client"
|
||||
export *
|
||||
}
|
||||
-89
@@ -7,92 +7,3 @@
|
||||
* Port used by the tunnel config service.
|
||||
*/
|
||||
#define CONFIG_SERVICE_PORT 1337
|
||||
|
||||
typedef struct PostQuantumCancelToken {
|
||||
void *context;
|
||||
} PostQuantumCancelToken;
|
||||
|
||||
/**
|
||||
* Called by the Swift side to signal that the quantum-secure key exchange should be cancelled.
|
||||
*
|
||||
* # 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);
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadRustRuntime
|
||||
import MullvadTypes
|
||||
|
||||
public final class ShadowsocksTransport: RESTTransport {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
framework module Shadowsocks {
|
||||
header "shadowsocks.h"
|
||||
link "libshadowsocks_proxy"
|
||||
export *
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "shadowsocks-proxy"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "rlib", "staticlib" ]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
shadowsocks-service = { workspace = true, features = [ "local", "stream-cipher", "local-http", "local-tunnel" ] }
|
||||
|
||||
tokio = { workspace = true }
|
||||
log = "0.4"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
|
||||
oslog = "0.2"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.build-dependencies]
|
||||
cbindgen = { version = "0.24.3", default-features = false }
|
||||
@@ -1,14 +0,0 @@
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
fn main() {
|
||||
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_language(cbindgen::Language::C)
|
||||
.generate()
|
||||
.expect("failed to generate bindings")
|
||||
.write_to_file("include/shadowsocks.h");
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
fn main() {}
|
||||
@@ -1,36 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct ProxyHandle {
|
||||
void *context;
|
||||
uint16_t port;
|
||||
} ProxyHandle;
|
||||
|
||||
/**
|
||||
* # 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);
|
||||
@@ -1,20 +0,0 @@
|
||||
use std::{net::SocketAddr, str::FromStr};
|
||||
|
||||
fn main() {
|
||||
let socketaddr = SocketAddr::from_str("185.65.135.117:443").unwrap();
|
||||
let password = "mullvad";
|
||||
let cipher = "aes-256-gcm";
|
||||
|
||||
let forward_address = SocketAddr::from_str("45.83.223.196:443").unwrap();
|
||||
|
||||
let (port, handle) =
|
||||
shadowsocks_proxy::run_forwarding_proxy(forward_address, socketaddr, password, cipher)
|
||||
.expect("failed to start SOCKS proxy");
|
||||
|
||||
println!("Running proxy on port {port}");
|
||||
|
||||
let _ = std::io::stdin().read_line(&mut String::new());
|
||||
println!("Stopping proxy");
|
||||
handle.stop();
|
||||
println!("Done");
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
use std::{
|
||||
net::{Ipv4Addr, SocketAddr},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let socketaddr = SocketAddr::from_str("185.65.135.117:443").unwrap();
|
||||
let password = "mullvad";
|
||||
let cipher = "aes-256-gcm";
|
||||
|
||||
let cipher_ptr = cipher.as_ptr();
|
||||
let cipher_size = cipher.as_bytes().len();
|
||||
|
||||
let password_ptr = password.as_ptr();
|
||||
let password_size = password.as_bytes().len();
|
||||
|
||||
let forward_address = Ipv4Addr::from_str("45.83.223.196").unwrap();
|
||||
let forward_address_bytes = forward_address.octets();
|
||||
let forward_address_ptr = forward_address_bytes.as_ptr();
|
||||
|
||||
let addr = Ipv4Addr::from_str("185.65.135.117").unwrap();
|
||||
let addr_bytes = addr.octets();
|
||||
let addr_ptr = addr_bytes.as_ptr();
|
||||
|
||||
let mut ctx = shadowsocks_proxy::ProxyHandle {
|
||||
port: 0,
|
||||
context: std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
let retval = unsafe {
|
||||
shadowsocks_proxy::start_shadowsocks_proxy(
|
||||
forward_address_ptr,
|
||||
forward_address_bytes.len(),
|
||||
443,
|
||||
addr_ptr,
|
||||
addr_bytes.len(),
|
||||
socketaddr.port(),
|
||||
password_ptr,
|
||||
password_size,
|
||||
cipher_ptr,
|
||||
cipher_size,
|
||||
&mut ctx as *mut _,
|
||||
)
|
||||
};
|
||||
if retval != 0 {
|
||||
println!("Failed to start proxy - {retval}");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("Running proxy on port {}", ctx.port);
|
||||
let _ = std::io::stdin().read_line(&mut String::new());
|
||||
println!("Stopping proxy");
|
||||
let retval = unsafe { shadowsocks_proxy::stop_shadowsocks_proxy(&mut ctx as *mut _) };
|
||||
if retval != 0 {
|
||||
println!("Failed to stop proxy");
|
||||
}
|
||||
println!("Done");
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct ProxyHandle {
|
||||
void *context;
|
||||
uint16_t port;
|
||||
} ProxyHandle;
|
||||
|
||||
/**
|
||||
* # 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);
|
||||
@@ -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"
|
||||
+5
-7
@@ -7,9 +7,9 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadRustRuntimeProxy
|
||||
import MullvadTypes
|
||||
import NetworkExtension
|
||||
import TalpidTunnelConfigClientProxy
|
||||
import WireGuardKitTypes
|
||||
|
||||
/// Writes data to the in-tunnel TCP connection
|
||||
@@ -90,15 +90,13 @@ func tcpConnectionReceive(
|
||||
/// - rawEphemeralKey: A raw pointer to the ephemeral private key of the device
|
||||
@_cdecl("swift_post_quantum_key_ready")
|
||||
func receivePostQuantumKey(
|
||||
rawPacketTunnel: UnsafeMutableRawPointer?,
|
||||
rawPostQuantumKeyReceiver: UnsafeMutableRawPointer?,
|
||||
rawPresharedKey: UnsafeMutableRawPointer?,
|
||||
rawEphemeralKey: UnsafeMutableRawPointer?
|
||||
) {
|
||||
guard
|
||||
let rawPacketTunnel,
|
||||
let postQuantumKeyReceiver = Unmanaged<NEPacketTunnelProvider>.fromOpaque(rawPacketTunnel)
|
||||
.takeUnretainedValue() as? PostQuantumKeyReceiving
|
||||
else { return }
|
||||
guard let rawPostQuantumKeyReceiver else { return }
|
||||
let postQuantumKeyReceiver = Unmanaged<PostQuantumKeyReceiver>.fromOpaque(rawPostQuantumKeyReceiver)
|
||||
.takeUnretainedValue()
|
||||
|
||||
guard
|
||||
let rawPresharedKey,
|
||||
+8
-8
@@ -7,10 +7,9 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadREST
|
||||
import MullvadRustRuntimeProxy
|
||||
import MullvadTypes
|
||||
import NetworkExtension
|
||||
import PacketTunnelCore
|
||||
import WireGuardKitTypes
|
||||
|
||||
public class PostQuantumKeyExchangeActor {
|
||||
@@ -29,7 +28,8 @@ public class PostQuantumKeyExchangeActor {
|
||||
unowned let packetTunnel: any TunnelProvider
|
||||
internal var negotiation: Negotiation?
|
||||
private var timer: DispatchSourceTimer?
|
||||
private var keyExchangeRetriesIterator: AnyIterator<Duration>
|
||||
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
|
||||
@@ -39,13 +39,13 @@ public class PostQuantumKeyExchangeActor {
|
||||
packetTunnel: any TunnelProvider,
|
||||
onFailure: @escaping (() -> Void),
|
||||
negotiationProvider: PostQuantumKeyNegotiating.Type = PostQuantumKeyNegotiator.self,
|
||||
keyExchangeRetriesIterator: AnyIterator<Duration> = REST.RetryStrategy.postQuantumKeyExchange
|
||||
.makeDelayIterator()
|
||||
iteratorProvider: @escaping () -> AnyIterator<Duration>
|
||||
) {
|
||||
self.packetTunnel = packetTunnel
|
||||
self.onFailure = onFailure
|
||||
self.negotiationProvider = negotiationProvider
|
||||
self.keyExchangeRetriesIterator = keyExchangeRetriesIterator
|
||||
self.iteratorProvider = iteratorProvider
|
||||
self.keyExchangeRetriesIterator = iteratorProvider()
|
||||
}
|
||||
|
||||
private func createTCPConnection(_ gatewayEndpoint: NWHostEndpoint) -> NWTCPConnection {
|
||||
@@ -93,7 +93,7 @@ public class PostQuantumKeyExchangeActor {
|
||||
gatewayIP: IPv4Gateway,
|
||||
devicePublicKey: privateKey.publicKey,
|
||||
presharedKey: ephemeralSharedKey,
|
||||
packetTunnel: packetTunnel,
|
||||
postQuantumKeyReceiver: packetTunnel,
|
||||
tcpConnection: inTunnelTCPConnection,
|
||||
postQuantumKeyExchangeTimeout: tcpConnectionTimeout
|
||||
) {
|
||||
@@ -116,7 +116,7 @@ public class PostQuantumKeyExchangeActor {
|
||||
|
||||
/// Resets the exponential timeout for successful key exchanges, and ends the current key exchange.
|
||||
public func reset() {
|
||||
keyExchangeRetriesIterator = REST.RetryStrategy.postQuantumKeyExchange.makeDelayIterator()
|
||||
keyExchangeRetriesIterator = iteratorProvider()
|
||||
endCurrentNegotiation()
|
||||
}
|
||||
|
||||
+5
-6
@@ -9,8 +9,6 @@
|
||||
import Foundation
|
||||
import MullvadTypes
|
||||
import NetworkExtension
|
||||
import PacketTunnelCore
|
||||
import TalpidTunnelConfigClientProxy
|
||||
import WireGuardKitTypes
|
||||
|
||||
// swiftlint:disable function_parameter_count
|
||||
@@ -19,7 +17,7 @@ public protocol PostQuantumKeyNegotiating {
|
||||
gatewayIP: IPv4Address,
|
||||
devicePublicKey: PublicKey,
|
||||
presharedKey: PrivateKey,
|
||||
packetTunnel: any TunnelProvider,
|
||||
postQuantumKeyReceiver: any TunnelProvider,
|
||||
tcpConnection: NWTCPConnection,
|
||||
postQuantumKeyExchangeTimeout: Duration
|
||||
) -> Bool
|
||||
@@ -41,19 +39,20 @@ public class PostQuantumKeyNegotiator: PostQuantumKeyNegotiating {
|
||||
gatewayIP: IPv4Address,
|
||||
devicePublicKey: PublicKey,
|
||||
presharedKey: PrivateKey,
|
||||
packetTunnel: any TunnelProvider,
|
||||
postQuantumKeyReceiver: any TunnelProvider,
|
||||
tcpConnection: NWTCPConnection,
|
||||
postQuantumKeyExchangeTimeout: Duration
|
||||
) -> Bool {
|
||||
// swiftlint:disable:next force_cast
|
||||
let packetTunnelPointer = Unmanaged.passUnretained(packetTunnel as! NEPacketTunnelProvider).toOpaque()
|
||||
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 },
|
||||
packetTunnelPointer,
|
||||
postQuantumKeyReceiver,
|
||||
opaqueConnection,
|
||||
&cancelToken,
|
||||
UInt64(postQuantumKeyExchangeTimeout.timeInterval)
|
||||
+1
-1
@@ -7,8 +7,8 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadRustRuntimeProxy
|
||||
import Network
|
||||
import Shadowsocks
|
||||
|
||||
/// A Swift wrapper around a Rust implementation of Shadowsocks proxy instance
|
||||
public class ShadowsocksProxy {
|
||||
+1
-1
@@ -7,9 +7,9 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadRustRuntimeProxy
|
||||
import MullvadTypes
|
||||
import Network
|
||||
import TunnelObfuscatorProxy
|
||||
|
||||
public protocol TunnelObfuscation {
|
||||
init(remoteAddress: IPAddress, tcpPort: UInt16)
|
||||
@@ -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);
|
||||
@@ -0,0 +1,5 @@
|
||||
framework module MullvadRustRuntimeProxy {
|
||||
header "mullvad_rust_runtime.h"
|
||||
link "libmullvad_ios"
|
||||
export *
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import MullvadPostQuantum
|
||||
@testable import MullvadRustRuntime
|
||||
@testable import MullvadTypes
|
||||
import NetworkExtension
|
||||
@testable import PacketTunnelCore
|
||||
+6
-4
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
@testable import MullvadMockData
|
||||
@testable import MullvadPostQuantum
|
||||
@testable import MullvadRustRuntime
|
||||
@testable import MullvadTypes
|
||||
import NetworkExtension
|
||||
@testable import PacketTunnelCore
|
||||
@@ -31,7 +31,8 @@ class MullvadPostQuantumTests: XCTestCase {
|
||||
onFailure: {
|
||||
negotiationFailure.fulfill()
|
||||
},
|
||||
negotiationProvider: FailedNegotiatorStub.self
|
||||
negotiationProvider: FailedNegotiatorStub.self,
|
||||
iteratorProvider: { AnyIterator { .milliseconds(10) } }
|
||||
)
|
||||
|
||||
let privateKey = PrivateKey()
|
||||
@@ -51,7 +52,7 @@ class MullvadPostQuantumTests: XCTestCase {
|
||||
negotiationFailure.fulfill()
|
||||
},
|
||||
negotiationProvider: FailedNegotiatorStub.self,
|
||||
keyExchangeRetriesIterator: AnyIterator { .milliseconds(10) }
|
||||
iteratorProvider: { AnyIterator { .milliseconds(10) } }
|
||||
)
|
||||
|
||||
let privateKey = PrivateKey()
|
||||
@@ -69,7 +70,8 @@ class MullvadPostQuantumTests: XCTestCase {
|
||||
onFailure: {
|
||||
unexpectedNegotiationFailure.fulfill()
|
||||
},
|
||||
negotiationProvider: SuccessfulNegotiatorStub.self
|
||||
negotiationProvider: SuccessfulNegotiatorStub.self,
|
||||
iteratorProvider: { AnyIterator { .milliseconds(10) } }
|
||||
)
|
||||
|
||||
let privateKey = PrivateKey()
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -6,8 +6,8 @@
|
||||
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
import MullvadRustRuntime
|
||||
import Network
|
||||
import TunnelObfuscation
|
||||
import XCTest
|
||||
|
||||
final class TunnelObfuscationTests: XCTestCase {
|
||||
File renamed without changes.
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// PostQuantumKeyReceiver.swift
|
||||
// MullvadTypes
|
||||
//
|
||||
// Created by Marco Nikic on 2024-07-04.
|
||||
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
import WireGuardKitTypes
|
||||
|
||||
public class PostQuantumKeyReceiver: PostQuantumKeyReceiving, TunnelProvider {
|
||||
unowned let tunnelProvider: NEPacketTunnelProvider
|
||||
|
||||
public init(tunnelProvider: NEPacketTunnelProvider) {
|
||||
self.tunnelProvider = tunnelProvider
|
||||
}
|
||||
|
||||
// MARK: - PostQuantumKeyReceiving
|
||||
|
||||
public func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) {
|
||||
guard let receiver = tunnelProvider as? PostQuantumKeyReceiving else { return }
|
||||
receiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
|
||||
}
|
||||
|
||||
public func keyExchangeFailed() {
|
||||
guard let receiver = tunnelProvider as? PostQuantumKeyReceiving else { return }
|
||||
receiver.keyExchangeFailed()
|
||||
}
|
||||
|
||||
// MARK: - TunnelProvider
|
||||
|
||||
public func createTCPConnectionThroughTunnel(
|
||||
to remoteEndpoint: NWEndpoint,
|
||||
enableTLS: Bool,
|
||||
tlsParameters TLSParameters: NWTLSParameters?,
|
||||
delegate: Any?
|
||||
) -> NWTCPConnection {
|
||||
tunnelProvider.createTCPConnectionThroughTunnel(
|
||||
to: remoteEndpoint,
|
||||
enableTLS: enableTLS,
|
||||
tlsParameters: TLSParameters,
|
||||
delegate: delegate
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import WireGuardKitTypes
|
||||
|
||||
public protocol PostQuantumKeyReceiving {
|
||||
public protocol PostQuantumKeyReceiving: AnyObject {
|
||||
func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey)
|
||||
func keyExchangeFailed()
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
//
|
||||
// NEPacketTunnelProvider+Extensions.swift
|
||||
// PacketTunnelCore
|
||||
// TunnelProvider.swift
|
||||
// MullvadTypes
|
||||
//
|
||||
// Created by Marco Nikic on 2024-06-12.
|
||||
// Created by Marco Nikic on 2024-07-04.
|
||||
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -10,6 +10,7 @@ import BackgroundTasks
|
||||
import MullvadLogging
|
||||
import MullvadMockData
|
||||
import MullvadREST
|
||||
import MullvadRustRuntime
|
||||
import MullvadSettings
|
||||
import MullvadTypes
|
||||
import Operations
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
|
||||
import Foundation
|
||||
import MullvadLogging
|
||||
import MullvadPostQuantum
|
||||
import MullvadREST
|
||||
import MullvadRustRuntime
|
||||
import MullvadSettings
|
||||
import MullvadTypes
|
||||
import NetworkExtension
|
||||
import PacketTunnelCore
|
||||
import TunnelObfuscation
|
||||
import WireGuardKitTypes
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
@@ -32,6 +31,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
private let multihopStateListener = MultihopStateListener()
|
||||
private let multihopUpdater: MultihopUpdater
|
||||
private let constraintsUpdater = RelayConstraintsUpdater()
|
||||
private lazy var postQuantumReceiver = {
|
||||
PostQuantumKeyReceiver(tunnelProvider: self)
|
||||
}()
|
||||
|
||||
override init() {
|
||||
Self.configureLogging()
|
||||
@@ -92,7 +94,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
protocolObfuscator: ProtocolObfuscator<UDPOverTCPObfuscator>()
|
||||
)
|
||||
|
||||
postQuantumActor = PostQuantumKeyExchangeActor(packetTunnel: self, onFailure: self.keyExchangeFailed)
|
||||
postQuantumActor = PostQuantumKeyExchangeActor(
|
||||
packetTunnel: postQuantumReceiver,
|
||||
onFailure: self.keyExchangeFailed,
|
||||
iteratorProvider: { REST.RetryStrategy.postQuantumKeyExchange.makeDelayIterator() }
|
||||
)
|
||||
|
||||
let urlRequestProxy = URLRequestProxy(dispatchQueue: internalQueue, transportProvider: transportProvider)
|
||||
appMessageHandler = AppMessageHandler(packetTunnelActor: actor, urlRequestProxy: urlRequestProxy)
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
import Foundation
|
||||
import MullvadLogging
|
||||
import MullvadREST
|
||||
import MullvadRustRuntime
|
||||
import MullvadTypes
|
||||
import NetworkExtension
|
||||
import TunnelObfuscation
|
||||
import WireGuardKitTypes
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MullvadRustRuntime
|
||||
import MullvadTypes
|
||||
import TunnelObfuscation
|
||||
|
||||
public protocol ProtocolObfuscation {
|
||||
func obfuscate(_ endpoint: MullvadEndpoint, settings: Settings, retryAttempts: UInt) -> MullvadEndpoint
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
import MullvadREST
|
||||
import MullvadRustRuntime
|
||||
import MullvadTypes
|
||||
import TunnelObfuscation
|
||||
import WireGuardKitTypes
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import MullvadRustRuntime
|
||||
@testable import MullvadTypes
|
||||
import Network
|
||||
@testable import TunnelObfuscation
|
||||
|
||||
struct TunnelObfuscationStub: TunnelObfuscation {
|
||||
var transportLayer: TransportLayer { .udp }
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// TunnelObfuscation.h
|
||||
// TunnelObfuscation
|
||||
//
|
||||
// Created by pronebird on 2023-06-23.
|
||||
// Copyright © 2022 Mullvad VPN AB. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for TunnelObfuscation.
|
||||
FOUNDATION_EXPORT double TunnelObfuscationVersionNumber;
|
||||
|
||||
//! Project version string for TunnelObfuscation.
|
||||
FOUNDATION_EXPORT const unsigned char TunnelObfuscationVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <TunnelObfuscation/PublicHeader.h>
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
framework module TunnelObfuscatorProxy {
|
||||
header "tunnel_obfuscator_proxy.h"
|
||||
link "libtunnel_obfuscator_proxy"
|
||||
export *
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
[package]
|
||||
name = "tunnel-obfuscator-proxy"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "rlib", "staticlib" ]
|
||||
bench = false
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
tunnel-obfuscation = { path = "../../../tunnel-obfuscation" }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
log = "0.4"
|
||||
oslog = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "ios")'.build-dependencies]
|
||||
cbindgen = { version = "0.24.3", default-features = false }
|
||||
@@ -1,14 +0,0 @@
|
||||
#[cfg(target_os = "ios")]
|
||||
fn main() {
|
||||
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_language(cbindgen::Language::C)
|
||||
.generate()
|
||||
.expect("failed to generate bindings")
|
||||
.write_to_file("include/tunnel_obfuscator_proxy.h");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
fn main() {}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct ProxyHandle {
|
||||
void *context;
|
||||
uint16_t port;
|
||||
} ProxyHandle;
|
||||
|
||||
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);
|
||||
@@ -1,92 +0,0 @@
|
||||
#![cfg(target_os = "ios")]
|
||||
|
||||
use std::{io, net::SocketAddr};
|
||||
use tokio::sync::oneshot;
|
||||
use tunnel_obfuscation::{create_obfuscator, Settings as ObfuscationSettings, Udp2TcpSettings};
|
||||
|
||||
mod ffi;
|
||||
pub use ffi::{start_tunnel_obfuscator_proxy, stop_tunnel_obfuscator_proxy, ProxyHandle};
|
||||
|
||||
pub struct TunnelObfuscatorRuntime {
|
||||
runtime: tokio::runtime::Runtime,
|
||||
settings: ObfuscationSettings,
|
||||
}
|
||||
|
||||
impl TunnelObfuscatorRuntime {
|
||||
pub fn new(peer: SocketAddr) -> io::Result<Self> {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
let settings = ObfuscationSettings::Udp2Tcp(Udp2TcpSettings { peer });
|
||||
|
||||
Ok(Self { runtime, settings })
|
||||
}
|
||||
|
||||
pub fn run(self) -> io::Result<(SocketAddr, TunnelObfuscatorHandle)> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
let (startup_tx, startup_rx) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
self.run_service_inner(rx, startup_tx);
|
||||
});
|
||||
|
||||
match startup_rx.blocking_recv() {
|
||||
Ok(Ok(endpoint)) => Ok((endpoint, TunnelObfuscatorHandle { tx })),
|
||||
Ok(Err(err)) => {
|
||||
let _ = tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
Err(io::Error::new(io::ErrorKind::Other, err))
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Tokio runtime crashed",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_service_inner(
|
||||
self,
|
||||
shutdown_rx: oneshot::Receiver<oneshot::Sender<()>>,
|
||||
startup_done_tx: oneshot::Sender<io::Result<SocketAddr>>,
|
||||
) {
|
||||
let Self {
|
||||
settings, runtime, ..
|
||||
} = self;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
runtime.spawn(async move {
|
||||
match create_obfuscator(&settings).await {
|
||||
Ok(obfuscator) => {
|
||||
let endpoint = obfuscator.endpoint();
|
||||
let _ = startup_done_tx.send(Ok(endpoint));
|
||||
let _ = obfuscator.run().await;
|
||||
}
|
||||
Err(err) => {
|
||||
let _ =
|
||||
startup_done_tx.send(Err(io::Error::new(io::ErrorKind::Other, err)));
|
||||
}
|
||||
}
|
||||
});
|
||||
if let Ok(shutdown_tx) = runtime.block_on(shutdown_rx) {
|
||||
std::mem::drop(runtime);
|
||||
let _ = shutdown_tx.send(());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunnelObfuscatorHandle {
|
||||
tx: oneshot::Sender<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
impl TunnelObfuscatorHandle {
|
||||
pub fn stop(self) {
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
let _ = self.tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "mullvad-ios"
|
||||
description = "Entry point for all FFI code on iOS"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
libc = "0.2"
|
||||
log = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
tonic = { workspace = true }
|
||||
tower = { workspace = true }
|
||||
tunnel-obfuscation = { path = "../tunnel-obfuscation" }
|
||||
oslog = "0.2"
|
||||
talpid-types = { path = "../talpid-types" }
|
||||
talpid-tunnel-config-client = { path = "../talpid-tunnel-config-client" }
|
||||
|
||||
shadowsocks-service = { workspace = true, features = [
|
||||
"local",
|
||||
"stream-cipher",
|
||||
"local-http",
|
||||
"local-tunnel",
|
||||
] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.build-dependencies]
|
||||
cbindgen = { version = "0.24.3", default-features = false }
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
bench = false
|
||||
@@ -0,0 +1,16 @@
|
||||
fn main() {
|
||||
#[cfg(target_os = "macos")]
|
||||
match std::env::var("TARGET").unwrap().as_str() {
|
||||
"aarch64-apple-ios" | "aarch64-apple-ios-sim" => {
|
||||
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
cbindgen::Builder::new()
|
||||
.with_autogen_warning("// This file is generated automatically. To update it forcefully, run `cargo run -p mullvad-ios --target aarch64-apple-ios`.")
|
||||
.with_crate(crate_dir)
|
||||
.with_language(cbindgen::Language::C)
|
||||
.generate()
|
||||
.expect("failed to generate bindings")
|
||||
.write_to_file("../ios/MullvadRustRuntime/include/mullvad_rust_runtime.h");
|
||||
}
|
||||
&_ => (),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#![cfg(target_os = "ios")]
|
||||
mod post_quantum_proxy;
|
||||
mod shadowsocks_proxy;
|
||||
mod tunnel_obfuscator_proxy;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ProxyHandle {
|
||||
pub context: *mut std::ffi::c_void,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static CONFIG_SERVICE_PORT: u16 = talpid_tunnel_config_client::CONFIG_SERVICE_PORT;
|
||||
|
||||
mod ios {
|
||||
use std::sync::OnceLock;
|
||||
use tokio::runtime::{Builder, Handle, Runtime};
|
||||
|
||||
static RUNTIME: OnceLock<Result<Runtime, String>> = OnceLock::new();
|
||||
|
||||
pub fn mullvad_ios_runtime() -> Result<Handle, String> {
|
||||
match RUNTIME.get_or_init(|| {
|
||||
Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.map_err(|error| ToString::to_string(&error))
|
||||
}) {
|
||||
Ok(runtime) => Ok(runtime.handle().clone()),
|
||||
Err(error) => Err(error.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use ios::*;
|
||||
+51
-56
@@ -1,5 +1,4 @@
|
||||
use super::{ios_tcp_connection::*, PostQuantumCancelToken};
|
||||
use crate::{request_ephemeral_peer_with, Error, RelayConfigService};
|
||||
use libc::c_void;
|
||||
use std::{
|
||||
future::Future,
|
||||
@@ -8,8 +7,9 @@ use std::{
|
||||
ptr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use talpid_tunnel_config_client::{request_ephemeral_peer_with, Error, RelayConfigService};
|
||||
use talpid_types::net::wireguard::{PrivateKey, PublicKey};
|
||||
use tokio::runtime::Builder;
|
||||
use tokio::runtime::Handle as TokioHandle;
|
||||
use tonic::transport::channel::Endpoint;
|
||||
use tower::util::service_fn;
|
||||
|
||||
@@ -22,6 +22,7 @@ pub unsafe fn run_post_quantum_psk_exchange(
|
||||
packet_tunnel: *const c_void,
|
||||
tcp_connection: *const c_void,
|
||||
post_quantum_key_exchange_timeout: u64,
|
||||
tokio_handle: TokioHandle,
|
||||
) -> Result<PostQuantumCancelToken, Error> {
|
||||
match unsafe {
|
||||
IOSRuntime::new(
|
||||
@@ -35,7 +36,7 @@ pub unsafe fn run_post_quantum_psk_exchange(
|
||||
Ok(runtime) => {
|
||||
let token = runtime.packet_tunnel.tcp_connection.clone();
|
||||
|
||||
runtime.run();
|
||||
runtime.run(tokio_handle);
|
||||
Ok(PostQuantumCancelToken {
|
||||
context: Arc::into_raw(token) as *mut _,
|
||||
})
|
||||
@@ -57,7 +58,6 @@ unsafe impl Send for SwiftContext {}
|
||||
unsafe impl Sync for SwiftContext {}
|
||||
|
||||
struct IOSRuntime {
|
||||
runtime: tokio::runtime::Runtime,
|
||||
pub_key: [u8; 32],
|
||||
ephemeral_key: [u8; 32],
|
||||
packet_tunnel: SwiftContext,
|
||||
@@ -72,18 +72,12 @@ impl IOSRuntime {
|
||||
tcp_connection: *const c_void,
|
||||
post_quantum_key_exchange_timeout: u64,
|
||||
) -> io::Result<Self> {
|
||||
let runtime = Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.worker_threads(2)
|
||||
.build()?;
|
||||
|
||||
let context = SwiftContext {
|
||||
packet_tunnel,
|
||||
tcp_connection: Arc::new(Mutex::new(ConnectionContext::new(tcp_connection))),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
runtime,
|
||||
pub_key,
|
||||
ephemeral_key,
|
||||
packet_tunnel: context,
|
||||
@@ -91,9 +85,9 @@ impl IOSRuntime {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(self) {
|
||||
std::thread::spawn(move || {
|
||||
self.run_service_inner();
|
||||
pub fn run(self, handle: TokioHandle) {
|
||||
handle.spawn(async move {
|
||||
self.run_service_inner().await;
|
||||
});
|
||||
}
|
||||
/// Creates a `RelayConfigService` using the in-tunnel TCP Connection provided by the Packet
|
||||
@@ -124,60 +118,61 @@ impl IOSRuntime {
|
||||
Ok((RelayConfigService::new(conn), conn_handle))
|
||||
}
|
||||
|
||||
fn run_service_inner(self) {
|
||||
let Self { runtime, .. } = self;
|
||||
|
||||
let packet_tunnel_ptr = self.packet_tunnel.packet_tunnel;
|
||||
runtime.block_on(async move {
|
||||
let (async_provider, shutdown_handle) = unsafe { match Self::ios_tcp_client(self.packet_tunnel).await {
|
||||
async fn run_service_inner(self) {
|
||||
let (async_provider, shutdown_handle) = unsafe {
|
||||
match Self::ios_tcp_client(self.packet_tunnel.clone()).await {
|
||||
Ok(result) => result,
|
||||
Err(error) => {
|
||||
log::error!("Failed to create iOS TCP client: {error}");
|
||||
swift_post_quantum_key_ready(packet_tunnel_ptr, ptr::null(), ptr::null());
|
||||
swift_post_quantum_key_ready(
|
||||
self.packet_tunnel.packet_tunnel,
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}};
|
||||
let ephemeral_pub_key = PrivateKey::from(self.ephemeral_key).public_key();
|
||||
}
|
||||
};
|
||||
let ephemeral_pub_key = PrivateKey::from(self.ephemeral_key).public_key();
|
||||
|
||||
tokio::select! {
|
||||
ephemeral_peer = request_ephemeral_peer_with(
|
||||
async_provider,
|
||||
PublicKey::from(self.pub_key),
|
||||
ephemeral_pub_key,
|
||||
true,
|
||||
false,
|
||||
) => {
|
||||
shutdown_handle.shutdown();
|
||||
match ephemeral_peer {
|
||||
Ok(peer) => {
|
||||
match peer.psk {
|
||||
Some(preshared_key) => unsafe {
|
||||
let preshared_key_bytes = preshared_key.as_bytes();
|
||||
swift_post_quantum_key_ready(packet_tunnel_ptr, preshared_key_bytes.as_ptr(), self.ephemeral_key.as_ptr());
|
||||
},
|
||||
None => {
|
||||
log::error!("No suitable peer was found");
|
||||
unsafe {
|
||||
swift_post_quantum_key_ready(packet_tunnel_ptr, ptr::null(), ptr::null());
|
||||
}
|
||||
tokio::select! {
|
||||
ephemeral_peer = request_ephemeral_peer_with(
|
||||
async_provider,
|
||||
PublicKey::from(self.pub_key),
|
||||
ephemeral_pub_key,
|
||||
true,
|
||||
false,
|
||||
) => {
|
||||
shutdown_handle.shutdown();
|
||||
match ephemeral_peer {
|
||||
Ok(peer) => {
|
||||
match peer.psk {
|
||||
Some(preshared_key) => unsafe {
|
||||
let preshared_key_bytes = preshared_key.as_bytes();
|
||||
swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, preshared_key_bytes.as_ptr(), self.ephemeral_key.as_ptr());
|
||||
},
|
||||
None => {
|
||||
log::error!("No suitable peer was found");
|
||||
unsafe {
|
||||
swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
log::error!("Key exchange failed {}", error);
|
||||
unsafe {
|
||||
swift_post_quantum_key_ready(packet_tunnel_ptr, ptr::null(), ptr::null());
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
log::error!("Key exchange failed {}", error);
|
||||
unsafe {
|
||||
swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ = tokio::time::sleep(std::time::Duration::from_secs(self.post_quantum_key_exchange_timeout)) => {
|
||||
shutdown_handle.shutdown();
|
||||
unsafe { swift_post_quantum_key_ready(packet_tunnel_ptr, ptr::null(), ptr::null()); }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_ = tokio::time::sleep(std::time::Duration::from_secs(self.post_quantum_key_exchange_timeout)) => {
|
||||
shutdown_handle.shutdown();
|
||||
unsafe { swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null()); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+17
-5
@@ -1,7 +1,7 @@
|
||||
pub mod ios_runtime;
|
||||
pub mod ios_tcp_connection;
|
||||
|
||||
use crate::ios_ffi::ios_runtime::run_post_quantum_psk_exchange;
|
||||
use ios_runtime::run_post_quantum_psk_exchange;
|
||||
use ios_tcp_connection::ConnectionContext;
|
||||
use libc::c_void;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
@@ -43,6 +43,7 @@ impl Drop for PostQuantumCancelToken {
|
||||
unsafe impl Send for PostQuantumCancelToken {}
|
||||
|
||||
/// 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
|
||||
@@ -52,6 +53,7 @@ pub unsafe extern "C" fn cancel_post_quantum_key_exchange(sender: *const PostQua
|
||||
let sender = unsafe { &*sender };
|
||||
sender.cancel();
|
||||
}
|
||||
|
||||
/// Called by the Swift side to signal that the Rust `PostQuantumCancelToken` can be safely dropped
|
||||
/// from memory.
|
||||
///
|
||||
@@ -130,16 +132,26 @@ pub unsafe extern "C" fn negotiate_post_quantum_key(
|
||||
.init();
|
||||
});
|
||||
|
||||
let pub_key_copy: [u8; 32] = unsafe { std::ptr::read(public_key as *const [u8; 32]) };
|
||||
let eph_key_copy: [u8; 32] = unsafe { std::ptr::read(ephemeral_key as *const [u8; 32]) };
|
||||
let pub_key: [u8; 32] = unsafe { std::ptr::read(public_key as *const [u8; 32]) };
|
||||
let eph_key: [u8; 32] = unsafe { std::ptr::read(ephemeral_key as *const [u8; 32]) };
|
||||
|
||||
let handle = match crate::mullvad_ios_runtime() {
|
||||
Ok(handle) => handle,
|
||||
Err(err) => {
|
||||
log::error!("Failed to obtain a handle to a tokio runtime: {err}");
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
match unsafe {
|
||||
run_post_quantum_psk_exchange(
|
||||
pub_key_copy,
|
||||
eph_key_copy,
|
||||
pub_key,
|
||||
eph_key,
|
||||
packet_tunnel,
|
||||
tcp_connection,
|
||||
post_quantum_key_exchange_timeout,
|
||||
handle,
|
||||
)
|
||||
} {
|
||||
Ok(token) => {
|
||||
+1
-6
@@ -1,4 +1,5 @@
|
||||
use super::{run_forwarding_proxy, ShadowsocksHandle};
|
||||
use crate::ProxyHandle;
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
@@ -7,12 +8,6 @@ use std::sync::Once;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
static INIT_LOGGING: Once = Once::new();
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ProxyHandle {
|
||||
pub context: *mut std::ffi::c_void,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
/// # 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.
|
||||
+21
-66
@@ -1,3 +1,4 @@
|
||||
use super::mullvad_ios_runtime;
|
||||
use shadowsocks_service::{
|
||||
config::{
|
||||
Config, ConfigType, LocalConfig, LocalInstanceConfig, ProtocolType, ServerInstanceConfig,
|
||||
@@ -10,10 +11,8 @@ use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener},
|
||||
str::FromStr,
|
||||
};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use tokio::task::JoinHandle;
|
||||
mod ffi;
|
||||
pub use ffi::{start_shadowsocks_proxy, stop_shadowsocks_proxy, ProxyHandle};
|
||||
|
||||
pub fn run_forwarding_proxy(
|
||||
forward_socket_addr: SocketAddr,
|
||||
@@ -22,49 +21,38 @@ pub fn run_forwarding_proxy(
|
||||
cipher: &str,
|
||||
) -> io::Result<(u16, ShadowsocksHandle)> {
|
||||
let runtime =
|
||||
ShadowsocksRuntime::new(forward_socket_addr, bridge_socket_addr, password, cipher)?;
|
||||
ShadowsocksService::new(forward_socket_addr, bridge_socket_addr, password, cipher)?;
|
||||
let port = runtime.port();
|
||||
let handle = runtime.run()?;
|
||||
|
||||
Ok((port, handle))
|
||||
}
|
||||
|
||||
struct ShadowsocksRuntime {
|
||||
runtime: tokio::runtime::Runtime,
|
||||
struct ShadowsocksService {
|
||||
config: Config,
|
||||
local_port: u16,
|
||||
}
|
||||
|
||||
pub struct ShadowsocksHandle {
|
||||
tx: oneshot::Sender<oneshot::Sender<()>>,
|
||||
abort_handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl ShadowsocksHandle {
|
||||
pub fn stop(self) {
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
let _ = self.tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
self.abort_handle.abort();
|
||||
}
|
||||
}
|
||||
|
||||
impl ShadowsocksRuntime {
|
||||
impl ShadowsocksService {
|
||||
pub fn new(
|
||||
forward_socket_addr: SocketAddr,
|
||||
bridge_socket_addr: SocketAddr,
|
||||
password: &str,
|
||||
cipher: &str,
|
||||
) -> io::Result<Self> {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
|
||||
let (config, local_port) =
|
||||
Self::create_config(forward_socket_addr, bridge_socket_addr, password, cipher)?;
|
||||
Ok(Self {
|
||||
runtime,
|
||||
config,
|
||||
local_port,
|
||||
})
|
||||
Ok(Self { config, local_port })
|
||||
}
|
||||
|
||||
pub fn port(&self) -> u16 {
|
||||
@@ -72,57 +60,24 @@ impl ShadowsocksRuntime {
|
||||
}
|
||||
|
||||
pub fn run(self) -> io::Result<ShadowsocksHandle> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
let (startup_tx, startup_rx) = oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
self.run_service_inner(rx, startup_tx);
|
||||
let runtime = mullvad_ios_runtime().map_err(io::Error::other)?;
|
||||
|
||||
let abort_handle = runtime.spawn(async move {
|
||||
self.run_service_inner().await;
|
||||
});
|
||||
|
||||
match startup_rx.blocking_recv() {
|
||||
Ok(Ok(_)) => Ok(ShadowsocksHandle { tx }),
|
||||
Ok(Err(err)) => {
|
||||
let _ = tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
Err(err)
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = tx.send(shutdown_tx);
|
||||
let _ = shutdown_rx.blocking_recv();
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Tokio runtime crashed",
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(ShadowsocksHandle { abort_handle })
|
||||
}
|
||||
|
||||
fn run_service_inner(
|
||||
self,
|
||||
shutdown_rx: oneshot::Receiver<oneshot::Sender<()>>,
|
||||
startup_done_tx: oneshot::Sender<io::Result<()>>,
|
||||
) {
|
||||
let Self {
|
||||
config, runtime, ..
|
||||
} = self;
|
||||
async fn run_service_inner(self) {
|
||||
let Self { config, .. } = self;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
runtime.spawn(async move {
|
||||
match Server::new(config).await {
|
||||
Ok(server) => {
|
||||
let _ = startup_done_tx.send(Ok(()));
|
||||
let _ = server.run().await;
|
||||
}
|
||||
Err(err) => {
|
||||
let _ = startup_done_tx.send(Err(err));
|
||||
}
|
||||
}
|
||||
});
|
||||
if let Ok(shutdown_tx) = runtime.block_on(shutdown_rx) {
|
||||
std::mem::drop(runtime);
|
||||
let _ = shutdown_tx.send(());
|
||||
}
|
||||
});
|
||||
let _ = Server::new(config)
|
||||
.await
|
||||
.map_err(io::Error::from)
|
||||
.expect("Could not create Shadowsocks server")
|
||||
.run()
|
||||
.await;
|
||||
}
|
||||
|
||||
pub fn create_config(
|
||||
+1
-8
@@ -1,6 +1,5 @@
|
||||
#![cfg(target_os = "ios")]
|
||||
|
||||
use super::{TunnelObfuscatorHandle, TunnelObfuscatorRuntime};
|
||||
use crate::ProxyHandle;
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
sync::Once,
|
||||
@@ -8,12 +7,6 @@ use std::{
|
||||
|
||||
static INIT_LOGGING: Once = Once::new();
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ProxyHandle {
|
||||
pub context: *mut std::ffi::c_void,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn start_tunnel_obfuscator_proxy(
|
||||
peer_address: *const u8,
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::{io, net::SocketAddr};
|
||||
use tokio::task::JoinHandle;
|
||||
use tunnel_obfuscation::{create_obfuscator, Settings as ObfuscationSettings, Udp2TcpSettings};
|
||||
|
||||
mod ffi;
|
||||
|
||||
use crate::mullvad_ios_runtime;
|
||||
|
||||
pub struct TunnelObfuscatorRuntime {
|
||||
settings: ObfuscationSettings,
|
||||
}
|
||||
|
||||
impl TunnelObfuscatorRuntime {
|
||||
pub fn new(peer: SocketAddr) -> io::Result<Self> {
|
||||
let settings = ObfuscationSettings::Udp2Tcp(Udp2TcpSettings { peer });
|
||||
|
||||
Ok(Self { settings })
|
||||
}
|
||||
|
||||
pub fn run(self) -> io::Result<(SocketAddr, TunnelObfuscatorHandle)> {
|
||||
let runtime = mullvad_ios_runtime().map_err(io::Error::other)?;
|
||||
|
||||
let obfuscator = runtime.block_on(async move {
|
||||
create_obfuscator(&self.settings)
|
||||
.await
|
||||
.map_err(io::Error::other)
|
||||
})?;
|
||||
|
||||
let endpoint = obfuscator.endpoint();
|
||||
let join_handle = runtime.spawn(async move {
|
||||
let _ = obfuscator.run().await;
|
||||
});
|
||||
|
||||
Ok((
|
||||
endpoint,
|
||||
TunnelObfuscatorHandle {
|
||||
obfuscator_abort_handle: join_handle,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunnelObfuscatorHandle {
|
||||
obfuscator_abort_handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl TunnelObfuscatorHandle {
|
||||
pub fn stop(self) {
|
||||
self.obfuscator_abort_handle.abort();
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ tonic-build = { workspace = true, default-features = false, features = [
|
||||
"transport",
|
||||
"prost",
|
||||
] }
|
||||
cbindgen = { version = "0.24.3", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
oslog = "0.2"
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
fn main() {
|
||||
tonic_build::compile_protos("proto/ephemeralpeer.proto").unwrap();
|
||||
match std::env::var("TARGET").unwrap().as_str() {
|
||||
"aarch64-apple-ios" | "aarch64-apple-ios-sim" => {
|
||||
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_language(cbindgen::Language::C)
|
||||
.generate()
|
||||
.expect("failed to generate bindings")
|
||||
.write_to_file("../ios/MullvadPostQuantum/talpid-tunnel-config-client/include/talpid_tunnel_config_client.h");
|
||||
}
|
||||
&_ => (),
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,6 @@ mod proto {
|
||||
tonic::include_proto!("ephemeralpeer");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub mod ios_ffi;
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
use libc::setsockopt;
|
||||
|
||||
|
||||
Reference in new issue
Block a user