punchnet-macos/Tun/PacketTunnelProvider.swift
2026-01-28 23:43:19 +08:00

137 lines
4.5 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 context: SDLContext?
private var rootTask: Task<Void, Error>?
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let logger = SDLLogger(level: .debug)
// host: "192.168.0.101", port: 1265
guard let options, let config = SDLConfiguration.parse(options: options) else {
completionHandler(TunnelError.invalidConfiguration)
return
}
//
guard self.context == nil else {
completionHandler(TunnelError.invalidContext)
return
}
//
let rsaCipher = try! CCRSACipher(keySize: 1024)
let aesChiper = CCAESChiper()
self.rootTask = Task {
do {
self.context = SDLContext(provider: self, config: config, rsaCipher: rsaCipher, aesCipher: aesChiper, logger: logger)
try await self.context?.start()
} catch let err {
logger.log("[PacketTunnelProvider] exit with error: \(err)")
exit(-1)
}
}
completionHandler(nil)
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to start the process of stopping the tunnel.
self.rootTask?.cancel()
Task {
await self.context?.stop()
}
self.context = nil
self.rootTask = nil
completionHandler()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
// Add code here to handle the message.
if let handler = completionHandler {
handler(messageData)
}
}
override func sleep(completionHandler: @escaping () -> Void) {
// Add code here to get ready to sleep.
completionHandler()
}
override func wake() {
// Add code here to wake up.
}
}
// ip
extension PacketTunnelProvider {
public static var viaInterface: NetworkInterface? = {
let interfaces = NetworkInterfaceManager.getInterfaces()
return interfaces.first {$0.name == "en0"}
}()
struct CCRSACipher: RSACipher {
var pubKey: String
let privateKeyDER: Data
init(keySize: Int) throws {
let (privateKey, publicKey) = try Self.loadKeys(keySize: keySize)
let privKeyStr = SwKeyConvert.PrivateKey.derToPKCS1PEM(privateKey)
self.pubKey = SwKeyConvert.PublicKey.derToPKCS8PEM(publicKey)
self.privateKeyDER = try SwKeyConvert.PrivateKey.pemToPKCS1DER(privKeyStr)
}
public func decode(data: Data) throws -> Data {
let tag = Data()
let (decryptedData, _) = try CC.RSA.decrypt(data, derKey: self.privateKeyDER, tag: tag, padding: .pkcs1, digest: .none)
return decryptedData
}
private static func loadKeys(keySize: Int) throws -> (Data, Data) {
if let privateKey = UserDefaults.standard.data(forKey: "privateKey"),
let publicKey = UserDefaults.standard.data(forKey: "publicKey") {
return (privateKey, publicKey)
} else {
let (privateKey, publicKey) = try CC.RSA.generateKeyPair(keySize)
UserDefaults.standard.setValue(privateKey, forKey: "privateKey")
UserDefaults.standard.setValue(publicKey, forKey: "publicKey")
return (privateKey, publicKey)
}
}
}
struct CCAESChiper: AESCipher {
func decypt(aesKey: Data, data: Data) throws -> Data {
let ivData = Data(aesKey.prefix(16))
return try CC.crypt(.decrypt, blockMode: .cbc, algorithm: .aes, padding: .pkcs7Padding, data: data, key: aesKey, iv: ivData)
}
func encrypt(aesKey: Data, data: Data) throws -> Data {
let ivData = Data(aesKey.prefix(16))
return try CC.crypt(.encrypt, blockMode: .cbc, algorithm: .aes, padding: .pkcs7Padding, data: data, key: aesKey, iv: ivData)
}
}
}