punchnet-macos/Tun/PacketTunnelProvider.swift

127 lines
4.0 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 NetworkExtension
enum TunnelError: Error {
case invalidConfiguration
case invalidContext
}
class PacketTunnelProvider: NEPacketTunnelProvider {
var contextActor: SDLContextActor?
private var rootTask: Task<Void, Error>?
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
//
SDLTunnelAppNotifier.shared.clear()
//
guard self.contextActor == nil else {
completionHandler(TunnelError.invalidContext)
return
}
//
let rsaCipher = try! CCRSACipher(keySize: 1024)
self.rootTask = Task {
// host: "192.168.0.101", port: 1265
guard let options, let config = await SDLConfiguration.parse(options: options) else {
completionHandler(TunnelError.invalidConfiguration)
return
}
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
await self.contextActor?.start()
try await self.contextActor?.waitForReady()
completionHandler(nil)
}
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to start the process of stopping the tunnel.
Task {
await self.contextActor?.stop()
self.contextActor = nil
self.rootTask?.cancel()
self.rootTask = nil
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.
completionHandler()
}
override func wake() {
// Add code here to wake up.
}
private func handleAppRequest(message: AppRequest) async throws -> Data? {
guard let contextActor = self.contextActor 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()
}
}
}
// ip
extension PacketTunnelProvider {
public static var viaInterface: NetworkInterface? = {
let interfaces = NetworkInterfaceManager.getInterfaces()
return interfaces.first {$0.name == "en0"}
}()
}