From 8c8006bc69fd0cc7eb870361ce3b1c60d391366d Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Wed, 4 Feb 2026 14:56:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=B3=BB=E7=BB=9F=E7=9A=84?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=80=80=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tun/Punchnet/Actors/ArpServerActor.swift | 37 +++++++++ Tun/Punchnet/ArpServer.swift | 51 ------------ Tun/Punchnet/SDLConfiguration.swift | 21 +++++ Tun/Punchnet/SDLContextActor.swift | 91 ++++++++++++++++----- Tun/Punchnet/SDLNetAddress.swift | 49 ----------- Tun/Punchnet/SDLTunnelProviderAdapter.swift | 84 ------------------- punchnet/Core/NoticeMessage.swift | 40 +-------- punchnet/Views/IndexView.swift | 5 -- 8 files changed, 128 insertions(+), 250 deletions(-) create mode 100644 Tun/Punchnet/Actors/ArpServerActor.swift delete mode 100644 Tun/Punchnet/ArpServer.swift delete mode 100644 Tun/Punchnet/SDLNetAddress.swift delete mode 100644 Tun/Punchnet/SDLTunnelProviderAdapter.swift diff --git a/Tun/Punchnet/Actors/ArpServerActor.swift b/Tun/Punchnet/Actors/ArpServerActor.swift new file mode 100644 index 0000000..6ada591 --- /dev/null +++ b/Tun/Punchnet/Actors/ArpServerActor.swift @@ -0,0 +1,37 @@ +// +// ArpServer.swift +// sdlan +// +// Created by 安礼成 on 2025/7/14. +// +import Foundation +import Darwin + +actor ArpServerActor { + private var known_macs: [UInt32:Data] = [:] + + init(known_macs: [UInt32:Data]) { + self.known_macs = known_macs + } + + func query(ip: UInt32) -> Data? { + return self.known_macs[ip] + } + + func append(ip: UInt32, mac: Data) { + self.known_macs[ip] = mac + } + + func remove(ip: UInt32) { + self.known_macs.removeValue(forKey: ip) + } + + func dropMacs(macs: [Data]) { + self.known_macs = self.known_macs.filter { !macs.contains($0.value) } + } + + func clear() { + self.known_macs = [:] + } + +} diff --git a/Tun/Punchnet/ArpServer.swift b/Tun/Punchnet/ArpServer.swift deleted file mode 100644 index d26d1b1..0000000 --- a/Tun/Punchnet/ArpServer.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ArpServer.swift -// sdlan -// -// Created by 安礼成 on 2025/7/14. -// -import Foundation -import Darwin - -final class ArpServer { - private var known_macs: [UInt32:Data] = [:] - private var lock = os_unfair_lock() - - init(known_macs: [UInt32:Data]) { - self.known_macs = known_macs - } - - func query(ip: UInt32) -> Data? { - return withLock { - return self.known_macs[ip] - } - } - - func append(ip: UInt32, mac: Data) { - withLock { - self.known_macs[ip] = mac - } - } - - func remove(ip: UInt32) { - withLock { - _ = self.known_macs.removeValue(forKey: ip) - } - } - - func clear() { - withLock { - self.known_macs = [:] - } - } - - private func withLock(_ body: () throws -> T) rethrows -> T { - os_unfair_lock_lock(&lock) - defer{ - os_unfair_lock_unlock(&lock) - } - - return try body() - } - -} diff --git a/Tun/Punchnet/SDLConfiguration.swift b/Tun/Punchnet/SDLConfiguration.swift index 4b10a66..45d96f1 100644 --- a/Tun/Punchnet/SDLConfiguration.swift +++ b/Tun/Punchnet/SDLConfiguration.swift @@ -25,6 +25,27 @@ public class SDLConfiguration { public let maskLen: UInt8 public let mac: Data public let networkDomain: String + + // ip地址 + var ipAddress: String { + return SDLUtil.int32ToIp(self.ip) + } + + // 掩码 + var maskAddress: String { + let len0 = 32 - maskLen + let num: UInt32 = (0xFFFFFFFF >> len0) << len0 + + return SDLUtil.int32ToIp(num) + } + + // 网络地址 + var netAddress: String { + let len0 = 32 - maskLen + let mask: UInt32 = (0xFFFFFFFF >> len0) << len0 + + return SDLUtil.int32ToIp(self.ip & mask) + } } // 当前的客户端版本 diff --git a/Tun/Punchnet/SDLContextActor.swift b/Tun/Punchnet/SDLContextActor.swift index 53fda12..5103b4e 100644 --- a/Tun/Punchnet/SDLContextActor.swift +++ b/Tun/Punchnet/SDLContextActor.swift @@ -35,7 +35,6 @@ actor SDLContextActor { private var udpHole: SDLUDPHole? private var udpHoleWorkers: [Task]? - nonisolated let providerAdapter: SDLTunnelProviderAdapter // dns的client对象 private var dnsClient: SDLDNSClient? private var dnsWorker: Task? @@ -48,7 +47,7 @@ actor SDLContextActor { private var readTask: Task<(), Never>? private var sessionManager: SessionManager - private var arpServer: ArpServer + private var arpServer: ArpServerActor // 网络状态变化的健康 private var monitor: SDLNetworkMonitor? @@ -63,14 +62,16 @@ actor SDLContextActor { // 处理内部的需要长时间运行的任务 private var loopChildWorkers: [Task] = [] + private let provider: NEPacketTunnelProvider + public init(provider: NEPacketTunnelProvider, config: SDLConfiguration, rsaCipher: RSACipher, aesCipher: AESCipher) { + self.provider = provider self.config = config self.rsaCipher = rsaCipher self.aesCipher = aesCipher self.sessionManager = SessionManager() - self.arpServer = ArpServer(known_macs: [:]) - self.providerAdapter = SDLTunnelProviderAdapter(provider: provider) + self.arpServer = ArpServerActor(known_macs: [:]) self.puncherActor = SDLPuncherActor(querySocketAddress: config.stunSocketAddress) self.proberActor = SDLNATProberActor(addressArray: config.stunProbeSocketAddressArray) @@ -153,7 +154,7 @@ actor SDLContextActor { break } let nePacket = NEPacket(data: packet, protocolFamily: 2) - self.providerAdapter.writePackets(packets: [nePacket]) + self.provider.packetFlow.writePacketObjects([nePacket]) } } @@ -188,7 +189,7 @@ actor SDLContextActor { await self.sendStunRequest() } - SDLLogger.shared.log("[SDLContext] pingTask cancel") + SDLLogger.shared.log("[SDLContext] udp pingTask cancel") } // 处理数据流 @@ -199,6 +200,8 @@ actor SDLContextActor { } try? await self.handleData(data: data) } + + SDLLogger.shared.log("[SDLContext] udp dataTask cancel") } // 处理控制信号 @@ -225,6 +228,8 @@ actor SDLContextActor { await self.handleRegisterAck(remoteAddress: remoteAddress, registerAck: registerAck) } } + + SDLLogger.shared.log("[SDLContext] udp signalTask cancel") } self.udpHole = udpHole @@ -293,13 +298,12 @@ actor SDLContextActor { SDLLogger.shared.log("[SDLContext] get registerSuperAck, aes_key len: \(self.aesKey!.count)", level: .info) // 服务器分配的tun网卡信息 do { - let ipAddress = try await self.providerAdapter.setNetworkSettings(networkAddress: self.config.networkAddress, dnsServer: SDLDNSClient.Helper.dnsServer) + try await self.setNetworkSettings(networkAddress: self.config.networkAddress, dnsServer: SDLDNSClient.Helper.dnsServer) SDLLogger.shared.log("[SDLContext] setNetworkSettings successed") - self.noticeClient?.send(data: NoticeMessage.ipAdress(ip: ipAddress)) self.startReader() } catch let err { SDLLogger.shared.log("[SDLContext] setTunnelNetworkSettings get error: \(err)", level: .error) - exit(-1) + self.provider.cancelTunnelWithError(err) } } @@ -313,7 +317,10 @@ actor SDLContextActor { case .invalidToken, .nodeDisabled: let alertNotice = NoticeMessage.alert(alert: errorMessage) self.noticeClient?.send(data: alertNotice) - exit(-1) + // 报告错误并退出 + let error = NSError(domain: "com.jihe.punchnet.tun", code: -1) + self.provider.cancelTunnelWithError(error) + case .noIpAddress, .networkFault, .internalFault: let alertNotice = NoticeMessage.alert(alert: errorMessage) self.noticeClient?.send(data: alertNotice) @@ -322,12 +329,11 @@ actor SDLContextActor { } - private func handleEvent(event: SDLEvent) throws { + private func handleEvent(event: SDLEvent) async throws { switch event { case .dropMacs(let dropMacsEvent): - // TODO SDLLogger.shared.log("[SDLContext] drop macs", level: .info) - () + await self.arpServer.dropMacs(macs: dropMacsEvent.macs) case .natChanged(let natChangedEvent): let dstMac = natChangedEvent.mac SDLLogger.shared.log("[SDLContext] natChangedEvent, dstMac: \(dstMac)", level: .info) @@ -349,7 +355,10 @@ actor SDLContextActor { case .networkShutdown(let shutdownEvent): let alertNotice = NoticeMessage.alert(alert: shutdownEvent.message) self.noticeClient?.send(data: alertNotice) - exit(-1) + + // 报告错误并退出 + let error = NSError(domain: "com.jihe.punchnet.tun", code: -2) + self.provider.cancelTunnelWithError(error) } } @@ -436,7 +445,7 @@ actor SDLContextActor { await self.routeLayerPacket(dstMac: arpPacket.senderMAC, type: .arp, data: response.marshal()) case .response: SDLLogger.shared.log("[SDLContext] get arp response packet", level: .debug) - self.arpServer.append(ip: arpPacket.senderIP, mac: arpPacket.senderMAC) + await self.arpServer.append(ip: arpPacket.senderIP, mac: arpPacket.senderMAC) } } else { SDLLogger.shared.log("[SDLContext] get invalid arp packet: \(arpPacket), target_ip: \(SDLUtil.int32ToIp(arpPacket.targetIP)), net ip: \(SDLUtil.int32ToIp(networkAddr.ip))", level: .debug) @@ -449,7 +458,7 @@ actor SDLContextActor { return } let packet = NEPacket(data: ipPacket.data, protocolFamily: 2) - self.providerAdapter.writePackets(packets: [packet]) + self.provider.packetFlow.writePacketObjects([packet]) default: SDLLogger.shared.log("[SDLContext] get invalid packet", level: .debug) } @@ -482,10 +491,11 @@ actor SDLContextActor { return } - let packets = await self.providerAdapter.readPackets() - let ipPackets = packets.compactMap { IPPacket($0) } - for ipPacket in ipPackets { - await self.dealPacket(packet: ipPacket) + let (packets, numbers) = await self.provider.packetFlow.readPackets() + for (data, number) in zip(packets, numbers) where number == 2 { + if let ipPacket = IPPacket(data) { + await self.dealPacket(packet: ipPacket) + } } } } @@ -505,12 +515,12 @@ actor SDLContextActor { // 本地通讯, 目标地址是本地服务器的ip地址 if dstIp == networkAddr.ip { let nePacket = NEPacket(data: packet.data, protocolFamily: 2) - self.providerAdapter.writePackets(packets: [nePacket]) + self.provider.packetFlow.writePacketObjects([nePacket]) return } // 查找arp缓存中是否有目标mac地址 - if let dstMac = self.arpServer.query(ip: dstIp) { + if let dstMac = await self.arpServer.query(ip: dstIp) { await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data) } else { @@ -564,6 +574,43 @@ actor SDLContextActor { } } + // 网络改变时需要重新配置网络信息 + private func setNetworkSettings(networkAddress: SDLConfiguration.NetworkAddress, dnsServer: String) async throws { + let routes: [NEIPv4Route] = [ + NEIPv4Route(destinationAddress: networkAddress.netAddress, subnetMask: networkAddress.maskAddress), + NEIPv4Route(destinationAddress: dnsServer, subnetMask: "255.255.255.255"), + ] + + // Add code here to start the process of connecting the tunnel. + let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8") + networkSettings.mtu = 1250 + + // 设置网卡的DNS解析 + let networkDomain = networkAddress.networkDomain + let dnsSettings = NEDNSSettings(servers: [dnsServer]) + dnsSettings.searchDomains = [networkDomain] + dnsSettings.matchDomains = [networkDomain] + dnsSettings.matchDomainsNoSearch = false + networkSettings.dnsSettings = dnsSettings + + let ipv4Settings = NEIPv4Settings(addresses: [networkAddress.ipAddress], subnetMasks: [networkAddress.maskAddress]) + // 设置路由表 + //NEIPv4Route.default() + ipv4Settings.includedRoutes = routes + networkSettings.ipv4Settings = ipv4Settings + // 网卡配置设置必须成功 + try await self.provider.setTunnelNetworkSettings(networkSettings) + } + + // 开始读取数据, 用单独的线程处理packetFlow + func readPackets() async -> [Data] { + let (packets, numbers) = await self.provider.packetFlow.readPackets() + return zip(packets, numbers).compactMap { (data, number) in + return number == 2 ? data : nil + } + } + + private func spawnLoop(_ body: @escaping () async throws -> Void) -> Task { return Task.detached { while !Task.isCancelled { diff --git a/Tun/Punchnet/SDLNetAddress.swift b/Tun/Punchnet/SDLNetAddress.swift deleted file mode 100644 index 5ab8a56..0000000 --- a/Tun/Punchnet/SDLNetAddress.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// SDLIPAddress.swift -// Tun -// -// Created by 安礼成 on 2024/3/4. -// - -import Foundation - -struct SDLNetAddress { - let ip: UInt32 - let maskLen: UInt8 - - // ip地址 - var ipAddress: String { - return intToIpAddress(self.ip) - } - - // 掩码 - var maskAddress: String { - let len0 = 32 - maskLen - let num: UInt32 = (0xFFFFFFFF >> len0) << len0 - - return intToIpAddress(num) - } - - // 网络地址 - var networkAddress: String { - let len0 = 32 - maskLen - let mask: UInt32 = (0xFFFFFFFF >> len0) << len0 - - return intToIpAddress(self.ip & mask) - } - - init(ip: UInt32, maskLen: UInt8) { - self.ip = ip - self.maskLen = maskLen - } - - private func intToIpAddress(_ num: UInt32) -> String { - let ip0 = (UInt8) (num >> 24 & 0xFF) - let ip1 = (UInt8) (num >> 16 & 0xFF) - let ip2 = (UInt8) (num >> 8 & 0xFF) - let ip3 = (UInt8) (num & 0xFF) - - return "\(ip0).\(ip1).\(ip2).\(ip3)" - } - -} diff --git a/Tun/Punchnet/SDLTunnelProviderAdapter.swift b/Tun/Punchnet/SDLTunnelProviderAdapter.swift deleted file mode 100644 index 4ef3e33..0000000 --- a/Tun/Punchnet/SDLTunnelProviderAdapter.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// SDLContext.swift -// Tun -// -// Created by 安礼成 on 2024/2/29. -// - -import Foundation -import NetworkExtension -import NIOCore -import Combine - -// 上下文环境变量,全局共享 -/* -1. 处理rsa的加解密逻辑 - */ - -final class SDLTunnelProviderAdapter { - - // 路由信息 - struct Route { - let dstAddress: String - let subnetMask: String - - var debugInfo: String { - return "\(dstAddress):\(subnetMask)" - } - } - - let provider: NEPacketTunnelProvider - - public init(provider: NEPacketTunnelProvider) { - self.provider = provider - } - - func writePackets(packets: [NEPacket]) { - //let packet = NEPacket(data: ipPacket.data, protocolFamily: 2) - self.provider.packetFlow.writePacketObjects(packets) - } - - // 网络改变时需要重新配置网络信息 - func setNetworkSettings(networkAddress: SDLConfiguration.NetworkAddress, dnsServer: String) async throws -> String { - let netAddress = SDLNetAddress(ip: networkAddress.ip, maskLen: networkAddress.maskLen) - let routes = [ - Route(dstAddress: netAddress.networkAddress, subnetMask: netAddress.maskAddress), - Route(dstAddress: dnsServer, subnetMask: "255.255.255.255") - ] - - // Add code here to start the process of connecting the tunnel. - let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8") - networkSettings.mtu = 1250 - - // 设置网卡的DNS解析 - - let networkDomain = networkAddress.networkDomain - let dnsSettings = NEDNSSettings(servers: [dnsServer]) - dnsSettings.searchDomains = [networkDomain] - dnsSettings.matchDomains = [networkDomain] - dnsSettings.matchDomainsNoSearch = false - networkSettings.dnsSettings = dnsSettings - SDLLogger.shared.log("[SDLTunnelProviderAdapter] Tun started at network ip: \(netAddress.ipAddress), mask: \(netAddress.maskAddress)", level: .info) - - let ipv4Settings = NEIPv4Settings(addresses: [netAddress.ipAddress], subnetMasks: [netAddress.maskAddress]) - // 设置路由表 - //NEIPv4Route.default() - ipv4Settings.includedRoutes = routes.map { route in - NEIPv4Route(destinationAddress: route.dstAddress, subnetMask: route.subnetMask) - } - networkSettings.ipv4Settings = ipv4Settings - // 网卡配置设置必须成功 - try await self.provider.setTunnelNetworkSettings(networkSettings) - - return netAddress.ipAddress - } - - // 开始读取数据, 用单独的线程处理packetFlow - func readPackets() async -> [Data] { - let (packets, numbers) = await self.provider.packetFlow.readPackets() - return zip(packets, numbers).compactMap { (data, number) in - return number == 2 ? data : nil - } - } - -} diff --git a/punchnet/Core/NoticeMessage.swift b/punchnet/Core/NoticeMessage.swift index 59f0350..df8a2ae 100644 --- a/punchnet/Core/NoticeMessage.swift +++ b/punchnet/Core/NoticeMessage.swift @@ -11,9 +11,7 @@ import NIOCore struct NoticeMessage { enum InboundMessage { case none - case upgradeMessage(prompt: String, address: String) case alertMessage(alert: String) - case ip(ip: String) } static func decodeMessage(buffer: inout ByteBuffer) -> InboundMessage { @@ -23,23 +21,10 @@ struct NoticeMessage { switch type { case 0x01: - if let len0 = buffer.readInteger(as: UInt16.self), - let prompt = buffer.readString(length: Int(len0)), - let len1 = buffer.readInteger(as: UInt16.self), - let address = buffer.readString(length: Int(len1)) { - return .upgradeMessage(prompt: prompt, address: address) - } - case 0x02: if let len0 = buffer.readInteger(as: UInt16.self), let alert = buffer.readString(length: Int(len0)) { return .alertMessage(alert: alert) } - - case 0x03: - if let len0 = buffer.readInteger(as: UInt16.self), - let ipAddress = buffer.readString(length: Int(len0)) { - return .ip(ip: ipAddress) - } default: return .none } @@ -47,39 +32,16 @@ struct NoticeMessage { return .none } - static func upgrade(prompt: String, address: String) -> Data { + static func alert(alert: String) -> Data { var data = Data() data.append(contentsOf: [0x01]) - data.append(contentsOf: lenBytes(UInt16(prompt.count))) - data.append(prompt.data(using: .utf8)!) - - data.append(contentsOf: lenBytes(UInt16(address.count))) - data.append(address.data(using: .utf8)!) - - return data - } - - static func alert(alert: String) -> Data { - var data = Data() - data.append(contentsOf: [0x02]) - data.append(contentsOf: lenBytes(UInt16(alert.count))) data.append(alert.data(using: .utf8)!) return data } - static func ipAdress(ip: String) -> Data { - var data = Data() - data.append(contentsOf: [0x03]) - - data.append(contentsOf: lenBytes(UInt16(ip.count))) - data.append(ip.data(using: .utf8)!) - - return data - } - private static func lenBytes(_ value: UInt16) -> [UInt8] { let byte1 = UInt8((value >> 8) & 0xFF) let bytes2 = UInt8(value & 0xFF) diff --git a/punchnet/Views/IndexView.swift b/punchnet/Views/IndexView.swift index 08e3eb9..20c1d71 100644 --- a/punchnet/Views/IndexView.swift +++ b/punchnet/Views/IndexView.swift @@ -222,8 +222,6 @@ struct IndexView: View { } .alert(isPresented: $showStunAlert) { switch self.message { - case .upgradeMessage(let prompt, _): - Alert(title: Text(prompt)) case .alertMessage(let alert): Alert(title: Text(alert)) default: @@ -250,9 +248,6 @@ struct IndexView: View { switch message { case .none: () - case .ip(let ip): - self.showIpAdress = true - self.ipAddress = ip default: self.message = message self.showStunAlert = true