punchnet-macos/Tun/PacketTunnelProvider.swift

119 lines
3.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// PacketTunnelProvider.swift
// punchnet
//
// Created by on 2025/8/3.
//
import Foundation
import NetworkExtension
enum TunnelError: Error {
case invalidConfiguration
case invalidContext
}
class PacketTunnelProvider: NEPacketTunnelProvider {
private var runtimeEnv: SDLRuntimeEnvironment?
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
//
guard self.runtimeEnv == nil else {
completionHandler(TunnelError.invalidContext)
return
}
guard let options, let config = SDLConfiguration.parse(options: options) else {
completionHandler(TunnelError.invalidConfiguration)
return
}
let rsaCipher = try! CCRSACipher(keySize: 1024)
self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self)
Task {
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?.submitCommand(command: .stop(completion: {
completionHandler()
}))
}
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
// Add code here to handle the message.
Task {
do {
let message = try AppRequest(serializedBytes: messageData)
let replyData = try await self.handleAppRequest(message: message)
completionHandler?(replyData)
} catch let err {
var reply = TunnelResponse()
reply.code = 1
reply.message = err.localizedDescription
let errorReplyData = try? reply.serializedData()
completionHandler?(errorReplyData)
}
}
}
override func sleep(completionHandler: @escaping () -> Void) {
// Add code here to get ready to sleep.
Task {
await self.runtimeEnv?.submitCommand(command: .stop(completion: {
SDLLogger.log("[PacketTunnelProvider] sleep")
}))
}
completionHandler()
}
override func wake() {
SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!")
// Add code here to wake up.
Task {
//
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 = await self.runtimeEnv?.getContextActor() else {
throw TunnelError.invalidContext
}
switch message.command {
case .changeExitNode(let changeExitNode):
let exitNodeIp = changeExitNode.ip
do {
try await contextActor.updateExitNode(exitNodeIp: exitNodeIp)
var reply = TunnelResponse()
reply.code = 0
reply.message = "操作成功"
return try reply.serializedData()
} catch let err {
var reply = TunnelResponse()
reply.code = 1
reply.message = err.localizedDescription
return try reply.serializedData()
}
case .none:
var reply = TunnelResponse()
reply.code = 1
reply.message = "无效请求"
return try reply.serializedData()
}
}
}