Compare commits
2 Commits
5b10f7de61
...
e10329ba2a
| Author | SHA1 | Date | |
|---|---|---|---|
| e10329ba2a | |||
| d3f5d7388f |
@ -5,6 +5,7 @@
|
||||
// Created by 安礼成 on 2025/8/3.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
|
||||
enum TunnelError: Error {
|
||||
@ -22,28 +23,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
return
|
||||
}
|
||||
|
||||
guard let options else {
|
||||
guard let options, let config = SDLConfiguration.parse(options: options) else {
|
||||
completionHandler(TunnelError.invalidConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
self.runtimeEnv = SDLRuntimeEnvironment(options: options)
|
||||
let rsaCipher = try! CCRSACipher(keySize: 1024)
|
||||
self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self)
|
||||
Task {
|
||||
do {
|
||||
try await self.runtimeEnv?.start(provider: self)
|
||||
completionHandler(nil)
|
||||
} catch let err {
|
||||
await self.runtimeEnv?.submitCommand(command: .start(completion: { err in
|
||||
completionHandler(err)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
// Add code here to start the process of stopping the tunnel.
|
||||
Task {
|
||||
await self.runtimeEnv?.stop()
|
||||
completionHandler()
|
||||
await self.runtimeEnv?.submitCommand(command: .stop(completion: {
|
||||
completionHandler()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,37 +67,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
override func sleep(completionHandler: @escaping () -> Void) {
|
||||
// Add code here to get ready to sleep.
|
||||
Task {
|
||||
await self.runtimeEnv?.stop()
|
||||
completionHandler()
|
||||
await self.runtimeEnv?.submitCommand(command: .stop(completion: {
|
||||
SDLLogger.log("[PacketTunnelProvider] sleep")
|
||||
}))
|
||||
}
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
override func wake() {
|
||||
SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!")
|
||||
// 启动monitor
|
||||
let monitor = SDLPathMonitor()
|
||||
// 启动监视器,允许重入
|
||||
monitor.start()
|
||||
SDLLogger.log("[PacketTunnelProvider] monitor started")
|
||||
|
||||
// Add code here to wake up.
|
||||
Task {
|
||||
|
||||
defer {
|
||||
monitor.stop()
|
||||
}
|
||||
|
||||
// 等待网络可达
|
||||
_ = await monitor.statusStream().first {$0 == .satisfied}
|
||||
SDLLogger.log("[PacketTunnelProvider] network is satisfied")
|
||||
// 重新启动
|
||||
try await self.runtimeEnv?.start(provider: self)
|
||||
await self.runtimeEnv?.submitCommand(command: .start(completion: { err in
|
||||
SDLLogger.log("[PacketTunnelProvider] wakeup and try start")
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func handleAppRequest(message: AppRequest) async throws -> Data? {
|
||||
guard let contextActor = self.runtimeEnv?.getContextActor() else {
|
||||
guard let contextActor = await self.runtimeEnv?.getContextActor() else {
|
||||
throw TunnelError.invalidContext
|
||||
}
|
||||
|
||||
@ -128,37 +116,3 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SDLRuntimeEnvironment {
|
||||
var contextActor: SDLContextActor?
|
||||
private var options: [String: NSObject]
|
||||
|
||||
init(options: [String: NSObject]) {
|
||||
self.options = options
|
||||
}
|
||||
|
||||
func start(provider: PacketTunnelProvider) async throws {
|
||||
// 重置通知中心
|
||||
SDLTunnelAppNotifier.shared.clear()
|
||||
|
||||
guard let config = await SDLConfiguration.parse(options: options) else {
|
||||
throw TunnelError.invalidConfiguration
|
||||
}
|
||||
|
||||
// 加密算法
|
||||
let rsaCipher = try! CCRSACipher(keySize: 1024)
|
||||
let contextActor = SDLContextActor(provider: provider, config: config, rsaCipher: rsaCipher)
|
||||
self.contextActor = contextActor
|
||||
await contextActor.start()
|
||||
}
|
||||
|
||||
func getContextActor() -> SDLContextActor? {
|
||||
return self.contextActor
|
||||
}
|
||||
|
||||
func stop() async {
|
||||
await self.contextActor?.stop()
|
||||
self.contextActor = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,13 +14,6 @@ import NIOCore
|
||||
1. 处理rsa的加解密逻辑
|
||||
*/
|
||||
actor SDLContextActor {
|
||||
enum ReadyState {
|
||||
case idle
|
||||
case starting
|
||||
case ready
|
||||
case failed(any Error)
|
||||
case stopped
|
||||
}
|
||||
|
||||
private enum UDPHoleKind: Equatable {
|
||||
case v4
|
||||
@ -36,8 +29,6 @@ actor SDLContextActor {
|
||||
}
|
||||
}
|
||||
|
||||
private var readyState: ReadyState = .idle
|
||||
|
||||
var config: SDLConfiguration
|
||||
// nat的网络类型
|
||||
var natType: SDLNATProberActor.NatType = .blocked
|
||||
@ -126,11 +117,6 @@ actor SDLContextActor {
|
||||
}
|
||||
|
||||
public func start() async {
|
||||
guard case .idle = self.readyState else {
|
||||
return
|
||||
}
|
||||
|
||||
self.readyState = .starting
|
||||
await self.startRuntime(resetNotifier: true)
|
||||
}
|
||||
|
||||
@ -164,20 +150,6 @@ actor SDLContextActor {
|
||||
// }
|
||||
}
|
||||
|
||||
public func sleep() async {
|
||||
SDLLogger.log("[SDLContext] sleep")
|
||||
await self.stopRuntime()
|
||||
}
|
||||
|
||||
public func wake() async {
|
||||
SDLLogger.log("[SDLContext] wakeup")
|
||||
|
||||
// 先尝试停止
|
||||
await self.stopRuntime()
|
||||
// 重新启动
|
||||
await self.startRuntime(resetNotifier: false)
|
||||
}
|
||||
|
||||
// 取消出口节点的时候,ip地址为: 0.0.0.0
|
||||
public func updateExitNode(exitNodeIp: String) async throws {
|
||||
if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 {
|
||||
@ -211,6 +183,7 @@ actor SDLContextActor {
|
||||
|
||||
group.addTask {
|
||||
for await event in quicClient.eventStream {
|
||||
try Task.checkCancellation()
|
||||
switch event {
|
||||
case .ready:
|
||||
readyContinuation.yield()
|
||||
@ -262,6 +235,7 @@ actor SDLContextActor {
|
||||
SDLLogger.log("[SDLContext] quic welcome: \(welcome)")
|
||||
// 注册
|
||||
await self.doRegisterSuper()
|
||||
SDLLogger.log("[SDLContext] quic doRegisterSuper")
|
||||
|
||||
// 任务取消机制
|
||||
self.registerTask = Task {
|
||||
@ -297,7 +271,7 @@ actor SDLContextActor {
|
||||
|
||||
self.handleRegisterSuperNak(nakPacket: registerSuperNak)
|
||||
case .peerInfo(let peerInfo):
|
||||
//SDLLogger.shared.log("[SDLContext] peer message: \(peerInfo)")
|
||||
SDLLogger.log("[SDLContext] peer message: \(peerInfo)")
|
||||
await self.puncherActor.handlePeerInfo(using: self.udpHole, udpHoleV6: self.udpHoleV6, peerInfo: peerInfo)
|
||||
case .event(let event):
|
||||
await self.handleEvent(event: event)
|
||||
@ -305,7 +279,7 @@ actor SDLContextActor {
|
||||
// 处理权限的请求问题
|
||||
await self.identifyStore.applyPolicyResponse(policyResponse)
|
||||
case .arpResponse(let arpResponse):
|
||||
//SDLLogger.shared.log("[SDLContext] get arp response: \(arpResponse)")
|
||||
SDLLogger.log("[SDLContext] get arp response: \(arpResponse)")
|
||||
await self.arpServer.handleArpResponse(arpResponse: arpResponse)
|
||||
}
|
||||
}
|
||||
@ -323,7 +297,7 @@ actor SDLContextActor {
|
||||
self.dnsWorker = nil
|
||||
|
||||
// 启动dns服务
|
||||
let dnsClient = DNSCloudClient(host: self.config.serverIp, port: 15353)
|
||||
let dnsClient = DNSCloudClient(host: self.config.serverHost, port: 15353)
|
||||
await dnsClient.start()
|
||||
SDLLogger.log("[SDLContext] dnsClient started")
|
||||
self.dnsClient = dnsClient
|
||||
@ -384,7 +358,9 @@ actor SDLContextActor {
|
||||
self.udpHoleWorkers = [messageTask]
|
||||
|
||||
// 开始探测nat的类型
|
||||
await self.probeNatType()
|
||||
Task {
|
||||
await self.probeNatType()
|
||||
}
|
||||
|
||||
return udpHole
|
||||
}
|
||||
@ -413,7 +389,6 @@ actor SDLContextActor {
|
||||
|
||||
// 处理context的停止问题
|
||||
public func stop() async {
|
||||
self.readyState = .stopped
|
||||
await self.stopRuntime()
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,6 @@ public class SDLConfiguration {
|
||||
let version: Int
|
||||
|
||||
let serverHost: String
|
||||
let serverIp: String
|
||||
let stunServers: [String]
|
||||
|
||||
lazy var stunSocketAddress: SocketAddress = {
|
||||
@ -77,7 +76,6 @@ public class SDLConfiguration {
|
||||
|
||||
public init(version: Int,
|
||||
serverHost: String,
|
||||
serverIp: String,
|
||||
stunServers: [String],
|
||||
clientId: String,
|
||||
networkAddress: NetworkAddress,
|
||||
@ -87,7 +85,6 @@ public class SDLConfiguration {
|
||||
exitNode: ExitNode?) {
|
||||
self.version = version
|
||||
self.serverHost = serverHost
|
||||
self.serverIp = serverIp
|
||||
self.stunServers = stunServers
|
||||
self.clientId = clientId
|
||||
self.networkAddress = networkAddress
|
||||
@ -102,7 +99,7 @@ public class SDLConfiguration {
|
||||
// 解析配置文件
|
||||
extension SDLConfiguration {
|
||||
|
||||
static func parse(options: [String: NSObject]) async -> SDLConfiguration? {
|
||||
static func parse(options: [String: NSObject]) -> SDLConfiguration? {
|
||||
guard let version = options["version"] as? Int,
|
||||
let serverHost = options["server_host"] as? String,
|
||||
let stunAssistHost = options["stun_assist_host"] as? String,
|
||||
@ -118,11 +115,6 @@ extension SDLConfiguration {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析dns域名所在的服务器地址
|
||||
guard let serverIp = await SDLUtil.resolveHostname(host: serverHost) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 网络出口配置是可选的
|
||||
var exitNode: ExitNode? = nil
|
||||
if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
|
||||
@ -131,7 +123,6 @@ extension SDLConfiguration {
|
||||
|
||||
return SDLConfiguration(version: version,
|
||||
serverHost: serverHost,
|
||||
serverIp: serverIp,
|
||||
stunServers: [serverHost, stunAssistHost],
|
||||
clientId: clientId,
|
||||
networkAddress: networkAddress,
|
||||
|
||||
117
Tun/SDLRuntimeEnvironment.swift
Normal file
117
Tun/SDLRuntimeEnvironment.swift
Normal file
@ -0,0 +1,117 @@
|
||||
import Foundation
|
||||
|
||||
enum SDLRuntimeEnvironmentCommand {
|
||||
case start(completion: @Sendable (Error?) -> Void)
|
||||
case stop(completion: @Sendable () -> Void)
|
||||
}
|
||||
|
||||
actor SDLRuntimeEnvironment {
|
||||
private enum State {
|
||||
case idle
|
||||
case running
|
||||
}
|
||||
|
||||
private var state: State = .idle
|
||||
private var contextActor: SDLContextActor?
|
||||
|
||||
private var config: SDLConfiguration
|
||||
private let rsaCipher: CCRSACipher
|
||||
private let provider: PacketTunnelProvider
|
||||
|
||||
private let commandStream: AsyncStream<SDLRuntimeEnvironmentCommand>
|
||||
private let commandCont: AsyncStream<SDLRuntimeEnvironmentCommand>.Continuation
|
||||
|
||||
private var commandTask: Task<Void, Never>?
|
||||
|
||||
init(config: SDLConfiguration, rsaCipher: CCRSACipher, provider: PacketTunnelProvider) {
|
||||
self.config = config
|
||||
self.rsaCipher = rsaCipher
|
||||
self.provider = provider
|
||||
|
||||
let pair = AsyncStream.makeStream(of: SDLRuntimeEnvironmentCommand.self)
|
||||
self.commandStream = pair.stream
|
||||
self.commandCont = pair.continuation
|
||||
}
|
||||
|
||||
func submitCommand(command: SDLRuntimeEnvironmentCommand) {
|
||||
self.commandCont.yield(command)
|
||||
}
|
||||
|
||||
func getContextActor() -> SDLContextActor? {
|
||||
self.contextActor
|
||||
}
|
||||
|
||||
func run() {
|
||||
let stream = self.commandStream
|
||||
|
||||
self.commandTask = Task { [weak self] in
|
||||
for await command in stream {
|
||||
guard let self else {
|
||||
break
|
||||
}
|
||||
|
||||
await self.handle(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handle(_ command: SDLRuntimeEnvironmentCommand) async {
|
||||
switch command {
|
||||
case .start(let handler):
|
||||
do {
|
||||
try await self.startCommand()
|
||||
handler(nil)
|
||||
} catch {
|
||||
handler(error)
|
||||
}
|
||||
|
||||
case .stop(let handler):
|
||||
await self.stopCommand()
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
private func startCommand() async throws {
|
||||
switch self.state {
|
||||
case .idle:
|
||||
SDLTunnelAppNotifier.shared.clear()
|
||||
|
||||
let contextActor = SDLContextActor(
|
||||
provider: provider,
|
||||
config: config,
|
||||
rsaCipher: self.rsaCipher
|
||||
)
|
||||
|
||||
self.contextActor = contextActor
|
||||
await contextActor.start()
|
||||
self.state = .running
|
||||
case .running:
|
||||
SDLLogger.log("[SDLRuntimeEnvironment] is running, ignore start command")
|
||||
}
|
||||
}
|
||||
|
||||
private func stopCommand() async {
|
||||
switch self.state {
|
||||
case .idle:
|
||||
SDLLogger.log("[SDLRuntimeEnvironment] is idle, ignore stop command")
|
||||
|
||||
case .running:
|
||||
let contextActor = self.contextActor
|
||||
self.contextActor = nil
|
||||
self.state = .idle
|
||||
|
||||
await contextActor?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
func shutdown() {
|
||||
self.commandCont.finish()
|
||||
self.commandTask?.cancel()
|
||||
self.commandTask = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.commandCont.finish()
|
||||
self.commandTask?.cancel()
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
import Foundation
|
||||
import Observation
|
||||
|
||||
@MainActor
|
||||
@Observable
|
||||
final class NetworkModel {
|
||||
@ObservationIgnored
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user