diff options
| -rw-r--r-- | ios/MullvadREST/ShadowSocksProxy.swift | 62 | ||||
| -rw-r--r-- | ios/MullvadREST/URLSessionTransport.swift | 30 | ||||
| -rw-r--r-- | ios/MullvadREST/shadowsocks-proxy/include/shadowsocks.h | 5 | ||||
| -rw-r--r-- | ios/MullvadREST/shadowsocks-proxy/src/bin/run.rs | 7 | ||||
| -rw-r--r-- | ios/MullvadREST/shadowsocks-proxy/src/bin/run_unsafe.rs | 7 | ||||
| -rw-r--r-- | ios/MullvadREST/shadowsocks-proxy/src/ffi.rs | 30 | ||||
| -rw-r--r-- | ios/MullvadREST/shadowsocks-proxy/src/lib.rs | 25 | ||||
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 8 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppDelegate.swift | 3 | ||||
| -rw-r--r-- | ios/MullvadVPN/TransportMonitor/TransportMonitor.swift | 12 | ||||
| -rw-r--r-- | ios/PacketTunnel/PacketTunnelProvider.swift | 3 | ||||
| -rw-r--r-- | ios/PacketTunnel/TunnelTransportProvider.swift | 7 |
12 files changed, 132 insertions, 67 deletions
diff --git a/ios/MullvadREST/ShadowSocksProxy.swift b/ios/MullvadREST/ShadowSocksProxy.swift index a905cdc9c7..8c54a101ee 100644 --- a/ios/MullvadREST/ShadowSocksProxy.swift +++ b/ios/MullvadREST/ShadowSocksProxy.swift @@ -10,19 +10,31 @@ import Foundation import Network import Shadowsocks -public class ShadowSocksProxy { +/// A Swift wrapper around a Rust implementation of Shadowsocks proxy instance +public class ShadowsocksProxy { private var proxyConfig: ProxyHandle - private let remoteAddress: IPAddress - private let remotePort: UInt16 + 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(remoteAddress: IPAddress, remotePort: UInt16, password: String, cipher: String) { + public init( + forwardAddress: IPAddress, + forwardPort: UInt16, + bridgeAddress: IPAddress, + bridgePort: UInt16, + password: String, + cipher: String + ) { proxyConfig = ProxyHandle(context: nil, port: 0) - self.remoteAddress = remoteAddress - self.remotePort = remotePort + self.forwardAddress = forwardAddress + self.forwardPort = forwardPort + self.bridgeAddress = bridgeAddress + self.bridgePort = bridgePort self.password = password self.cipher = cipher } @@ -47,25 +59,21 @@ public class ShadowSocksProxy { guard didStart == false else { return } didStart = true - // Get the raw bytes of `addr.rawValue` - remoteAddress.rawValue.withUnsafeBytes { unsafeAddressPointer in - - // Rebind the raw bytes to an array of bytes, and get a pointer to its beginning - let rawAddr = unsafeAddressPointer.bindMemory(to: UInt8.self).baseAddress - - // Get the raw bytes access to `proxyConfig` - _ = withUnsafeMutablePointer(to: &proxyConfig) { config in - start_shadowsocks_proxy( - rawAddr, - UInt(remoteAddress.rawValue.count), - remotePort, - password, - UInt(password.count), - cipher, - UInt(cipher.count), - config - ) - } + // 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 + ) } } @@ -76,8 +84,8 @@ public class ShadowSocksProxy { guard didStart == true else { return } didStart = false - _ = withUnsafePointer(to: proxyConfig) { pointer in - stop_shadowsocks_proxy(UnsafeMutablePointer(mutating: pointer)) + _ = withUnsafeMutablePointer(to: &proxyConfig) { config in + stop_shadowsocks_proxy(config) } } } diff --git a/ios/MullvadREST/URLSessionTransport.swift b/ios/MullvadREST/URLSessionTransport.swift index 0bb765c686..0be25162a4 100644 --- a/ios/MullvadREST/URLSessionTransport.swift +++ b/ios/MullvadREST/URLSessionTransport.swift @@ -34,22 +34,32 @@ extension REST { } public final class URLSessionShadowSocksTransport: RESTTransport { + /// The Shadowsocks proxy instance that proxies all the traffic it receives + private let shadowSocksProxy: ShadowsocksProxy + /// The IPv4 representation of the loopback address used by `shadowSocksProxy` + private let localhost = "127.0.0.1" + + /// The `URLSession` used to send requests via `shadowSocksProxy` + public let urlSession: URLSession + public var name: String { return "shadow-socks-url-session" } - public let urlSession: URLSession - private let shadowSocksProxy: ShadowSocksProxy - public init( urlSession: URLSession, shadowSocksConfiguration: ServerShadowsocks, - shadowSocksBridgeRelay: BridgeRelay + shadowSocksBridgeRelay: BridgeRelay, + addressCache: REST.AddressCache ) { self.urlSession = urlSession - shadowSocksProxy = ShadowSocksProxy( - remoteAddress: shadowSocksBridgeRelay.ipv4AddrIn, - remotePort: shadowSocksConfiguration.port, + let apiAddress = addressCache.getCurrentEndpoint() + + shadowSocksProxy = ShadowsocksProxy( + forwardAddress: apiAddress.ip, + forwardPort: apiAddress.port, + bridgeAddress: shadowSocksBridgeRelay.ipv4AddrIn, + bridgePort: shadowSocksConfiguration.port, password: shadowSocksConfiguration.password, cipher: shadowSocksConfiguration.cipher ) @@ -59,14 +69,14 @@ extension REST { _ request: URLRequest, completion: @escaping (Data?, URLResponse?, Swift.Error?) -> Void ) -> Cancellable { - // Start the shadow socks proxy in order to get a local port + // Start the Shadowsocks proxy in order to get a local port shadowSocksProxy.start() - // Copy the URL request and rewrite the host and port to point to the shadow socks proxy instance + // Copy the URL request and rewrite the host and port to point to the Shadowsocks proxy instance var urlRequestCopy = request urlRequestCopy.url = request.url.flatMap { url in var components = URLComponents(url: url, resolvingAgainstBaseURL: false) - components?.host = "127.0.0.1" + components?.host = localhost components?.port = Int(shadowSocksProxy.localPort()) return components?.url } diff --git a/ios/MullvadREST/shadowsocks-proxy/include/shadowsocks.h b/ios/MullvadREST/shadowsocks-proxy/include/shadowsocks.h index 487199ecc5..1a0a856d8d 100644 --- a/ios/MullvadREST/shadowsocks-proxy/include/shadowsocks.h +++ b/ios/MullvadREST/shadowsocks-proxy/include/shadowsocks.h @@ -16,7 +16,10 @@ typedef struct ProxyHandle { * `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 *addr, +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, diff --git a/ios/MullvadREST/shadowsocks-proxy/src/bin/run.rs b/ios/MullvadREST/shadowsocks-proxy/src/bin/run.rs index 073bd9cc02..1b096a5335 100644 --- a/ios/MullvadREST/shadowsocks-proxy/src/bin/run.rs +++ b/ios/MullvadREST/shadowsocks-proxy/src/bin/run.rs @@ -5,8 +5,11 @@ fn main() { let password = "mullvad"; let cipher = "aes-256-gcm"; - let (port, handle) = shadowsocks_proxy::run_forwarding_proxy(socketaddr, password, cipher) - .expect("failed to start SOCKS proxy"); + 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}"); diff --git a/ios/MullvadREST/shadowsocks-proxy/src/bin/run_unsafe.rs b/ios/MullvadREST/shadowsocks-proxy/src/bin/run_unsafe.rs index 1a3be6d541..805d1147a4 100644 --- a/ios/MullvadREST/shadowsocks-proxy/src/bin/run_unsafe.rs +++ b/ios/MullvadREST/shadowsocks-proxy/src/bin/run_unsafe.rs @@ -14,6 +14,10 @@ fn main() { 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(); @@ -25,6 +29,9 @@ fn main() { let retval = unsafe { shadowsocks_proxy::start_shadowsocks_proxy( + forward_address_ptr, + forward_address_bytes.len(), + 443, addr_ptr, addr_bytes.len(), socketaddr.port(), diff --git a/ios/MullvadREST/shadowsocks-proxy/src/ffi.rs b/ios/MullvadREST/shadowsocks-proxy/src/ffi.rs index d8c575ef7e..fc083f18bf 100644 --- a/ios/MullvadREST/shadowsocks-proxy/src/ffi.rs +++ b/ios/MullvadREST/shadowsocks-proxy/src/ffi.rs @@ -21,6 +21,9 @@ pub struct ProxyHandle { /// instance. #[no_mangle] pub unsafe extern "C" fn start_shadowsocks_proxy( + forward_address: *const u8, + forward_address_len: usize, + forward_port: u16, addr: *const u8, addr_len: usize, port: u16, @@ -37,13 +40,23 @@ pub unsafe extern "C" fn start_shadowsocks_proxy( .init(); }); + let forward_ip = if let Some(forward_address) = + unsafe { parse_ip_addr(forward_address, forward_address_len) } + { + forward_address + } else { + return -1; + }; + + let forward_socket_addr = SocketAddr::new(forward_ip, forward_port); + let bridge_ip = if let Some(addr) = unsafe { parse_ip_addr(addr, addr_len) } { addr } else { return -1; }; - let bridge_addr = SocketAddr::new(bridge_ip, port); + let bridge_socket_addr = SocketAddr::new(bridge_ip, port); let password = if let Some(password) = unsafe { parse_str(password, password_len) } { password @@ -57,13 +70,14 @@ pub unsafe extern "C" fn start_shadowsocks_proxy( return -1; }; - let (port, handle) = match run_forwarding_proxy(bridge_addr, &password, &cipher) { - Ok((port, handle)) => (port, handle), - Err(err) => { - log::error!("Failed to run HTTP proxy {}", err); - return err.raw_os_error().unwrap_or(-1); - } - }; + let (port, handle) = + match run_forwarding_proxy(forward_socket_addr, bridge_socket_addr, &password, &cipher) { + Ok((port, handle)) => (port, handle), + Err(err) => { + log::error!("Failed to run HTTP proxy {}", err); + return err.raw_os_error().unwrap_or(-1); + } + }; let handle = Box::new(handle); unsafe { diff --git a/ios/MullvadREST/shadowsocks-proxy/src/lib.rs b/ios/MullvadREST/shadowsocks-proxy/src/lib.rs index 66398cb9eb..3388280782 100644 --- a/ios/MullvadREST/shadowsocks-proxy/src/lib.rs +++ b/ios/MullvadREST/shadowsocks-proxy/src/lib.rs @@ -16,11 +16,13 @@ mod ffi; pub use ffi::{start_shadowsocks_proxy, stop_shadowsocks_proxy, ProxyHandle}; pub fn run_forwarding_proxy( - bridge_addr: SocketAddr, + forward_socket_addr: SocketAddr, + bridge_socket_addr: SocketAddr, password: &str, cipher: &str, ) -> io::Result<(u16, ShadowsocksHandle)> { - let runtime = ShadowsocksRuntime::new(bridge_addr, password, cipher)?; + let runtime = + ShadowsocksRuntime::new(forward_socket_addr, bridge_socket_addr, password, cipher)?; let port = runtime.port(); let handle = runtime.run()?; @@ -46,12 +48,18 @@ impl ShadowsocksHandle { } impl ShadowsocksRuntime { - pub fn new(bridge_addr: SocketAddr, password: &str, cipher: &str) -> io::Result<Self> { + 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(bridge_addr, password, cipher)?; + let (config, local_port) = + Self::create_config(forward_socket_addr, bridge_socket_addr, password, cipher)?; Ok(Self { runtime, config, @@ -118,7 +126,8 @@ impl ShadowsocksRuntime { } pub fn create_config( - bridge_addr: SocketAddr, + forward_socket_addr: SocketAddr, + bridge_socket_addr: SocketAddr, password: &str, cipher: &str, ) -> io::Result<(Config, u16)> { @@ -127,9 +136,7 @@ impl ShadowsocksRuntime { let bind_addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), free_port); let mut local_config = LocalConfig::new_with_addr(bind_addr.into(), ProtocolType::Tunnel); - local_config.forward_addr = - // TODO: Remove hardcoded API address - Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(45, 83, 223, 196)), 443).into()); + local_config.forward_addr = Some(forward_socket_addr.into()); cfg.local = vec![LocalInstanceConfig::with_local_config(local_config)]; let cipher = match CipherKind::from_str(cipher) { @@ -142,7 +149,7 @@ impl ShadowsocksRuntime { } }; let server_config = ServerInstanceConfig::with_server_config(ServerConfig::new( - bridge_addr, + bridge_socket_addr, password, cipher, )); diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 57a6c6f324..b700a6199f 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 01F1FF1C29F06124007083C3 /* ShadowSocksProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F1FF1B29F06124007083C3 /* ShadowSocksProxy.swift */; }; + 01F1FF1C29F06124007083C3 /* ShadowsocksProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F1FF1B29F06124007083C3 /* ShadowsocksProxy.swift */; }; 01F1FF1E29F0627D007083C3 /* libshadowsocks_proxy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01F1FF1D29F0627D007083C3 /* libshadowsocks_proxy.a */; }; 062B45A328FD4CA700746E77 /* le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 06799AB428F98CE700ACD94E /* le_root_cert.cer */; }; 062B45AE28FD503000746E77 /* WireGuardKit in Frameworks */ = {isa = PBXBuildFile; productRef = 062B45AD28FD503000746E77 /* WireGuardKit */; }; @@ -638,7 +638,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 01F1FF1B29F06124007083C3 /* ShadowSocksProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowSocksProxy.swift; sourceTree = "<group>"; }; + 01F1FF1B29F06124007083C3 /* ShadowsocksProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksProxy.swift; sourceTree = "<group>"; }; 01F1FF1D29F0627D007083C3 /* libshadowsocks_proxy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libshadowsocks_proxy.a; path = ../target/debug/libshadowsocks_proxy.a; sourceTree = "<group>"; }; 062B45BB28FD8C3B00746E77 /* RESTDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTDefaults.swift; sourceTree = "<group>"; }; 063687AF28EB083800BE7161 /* ProxyURLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyURLRequest.swift; sourceTree = "<group>"; }; @@ -1179,8 +1179,8 @@ 06FAE66528F83CA30033DD93 /* RESTURLSession.swift */, 06FAE67728F83CA40033DD93 /* ServerRelaysResponse.swift */, 06FAE66B28F83CA30033DD93 /* SSLPinningURLSessionDelegate.swift */, + 01F1FF1B29F06124007083C3 /* ShadowsocksProxy.swift */, 06FAE67C28F83CA50033DD93 /* URLSessionTransport.swift */, - 01F1FF1B29F06124007083C3 /* ShadowSocksProxy.swift */, ); path = MullvadREST; sourceTree = "<group>"; @@ -2566,7 +2566,7 @@ 06799AEA28F98E4800ACD94E /* RESTProxy.swift in Sources */, 06799ADD28F98E4800ACD94E /* RESTError.swift in Sources */, 06799ADB28F98E4800ACD94E /* RESTProxyFactory.swift in Sources */, - 01F1FF1C29F06124007083C3 /* ShadowSocksProxy.swift in Sources */, + 01F1FF1C29F06124007083C3 /* ShadowsocksProxy.swift in Sources */, 06799AF228F98E4800ACD94E /* RESTAccessTokenManager.swift in Sources */, 06799AF328F98E4800ACD94E /* RESTAuthenticationProxy.swift in Sources */, 06799AE628F98E4800ACD94E /* ServerRelaysResponse.swift in Sources */, diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 087d7142bc..b5ee97034d 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -95,7 +95,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD transportMonitor = TransportMonitor( tunnelManager: tunnelManager, tunnelStore: tunnelStore, - relayCacheTracker: relayCacheTracker + relayCacheTracker: relayCacheTracker, + addressCache: addressCache ) #if targetEnvironment(simulator) diff --git a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift index c700f69b14..710a890e6a 100644 --- a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift +++ b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift @@ -18,15 +18,22 @@ final class TransportMonitor: RESTTransportProvider { private let urlSessionTransport: REST.URLSessionTransport private let relayCacheTracker: RelayCacheTracker private let logger = Logger(label: "TransportMonitor") + private let addressCache: REST.AddressCache // MARK: - // MARK: Public API - init(tunnelManager: TunnelManager, tunnelStore: TunnelStore, relayCacheTracker: RelayCacheTracker) { + init( + tunnelManager: TunnelManager, + tunnelStore: TunnelStore, + relayCacheTracker: RelayCacheTracker, + addressCache: REST.AddressCache + ) { self.tunnelManager = tunnelManager self.tunnelStore = tunnelStore self.relayCacheTracker = relayCacheTracker + self.addressCache = addressCache urlSessionTransport = REST.URLSessionTransport(urlSession: REST.makeURLSession()) } @@ -54,7 +61,8 @@ final class TransportMonitor: RESTTransportProvider { let transport = REST.URLSessionShadowSocksTransport( urlSession: shadowSocksURLSession, shadowSocksConfiguration: shadowSocksConfiguration, - shadowSocksBridgeRelay: shadowSocksBridgeRelay + shadowSocksBridgeRelay: shadowSocksBridgeRelay, + addressCache: addressCache ) shadowSocksTransport = transport diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index bca20bfed9..d58b4e0e51 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -154,7 +154,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { let urlSessionTransport = REST.URLSessionTransport(urlSession: urlSession) let transportProvider = TunnelTransportProvider( urlSessionTransport: urlSessionTransport, - relayCache: relayCache + relayCache: relayCache, + addressCache: addressCache ) let proxyFactory = REST.ProxyFactory.makeProxyFactory( diff --git a/ios/PacketTunnel/TunnelTransportProvider.swift b/ios/PacketTunnel/TunnelTransportProvider.swift index a0f7e275ff..417f6904ff 100644 --- a/ios/PacketTunnel/TunnelTransportProvider.swift +++ b/ios/PacketTunnel/TunnelTransportProvider.swift @@ -16,10 +16,12 @@ final class TunnelTransportProvider: RESTTransportProvider { private let urlSessionTransport: REST.URLSessionTransport private let relayCache: RelayCache private let logger = Logger(label: "TunnelTransportProvider") + private let addressCache: REST.AddressCache - init(urlSessionTransport: REST.URLSessionTransport, relayCache: RelayCache) { + init(urlSessionTransport: REST.URLSessionTransport, relayCache: RelayCache, addressCache: REST.AddressCache) { self.urlSessionTransport = urlSessionTransport self.relayCache = relayCache + self.addressCache = addressCache } func transport() -> MullvadREST.RESTTransport? { @@ -43,7 +45,8 @@ final class TunnelTransportProvider: RESTTransportProvider { let shadowSocksTransport = REST.URLSessionShadowSocksTransport( urlSession: shadowSocksURLSession, shadowSocksConfiguration: shadowSocksConfiguration, - shadowSocksBridgeRelay: shadowSocksBridgeRelay + shadowSocksBridgeRelay: shadowSocksBridgeRelay, + addressCache: addressCache ) return shadowSocksTransport |
