1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
//
// ShadowsocksProxy.swift
// MullvadREST
//
// Created by Emils on 19/04/2023.
// Copyright © 2025 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: @unchecked Sendable {
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)
}
}
}
|