// // SDLHoleDataProcessor.swift // Tun // // Created by 安礼成 on 2026/4/14. // import Foundation final class SDLHoleDataProcessor { enum ProcessingAction { case sendARPReply(dstMac: Data, data: Data) case appendARP(ip: UInt32, mac: Data) case writeToTun(packetData: Data, identityID: UInt32) case requestPolicy(srcIdentityID: UInt32) case none } struct ProcessingPlan { let inboundBytes: Int let action: ProcessingAction } private let networkAddress: SDLConfiguration.NetworkAddress private let dataCipher: CCDataCipher? private let snapshotPublisher: SnapshotPublisher private let flowSessionManager: SDLFlowSessionManager init(networkAddress: SDLConfiguration.NetworkAddress, dataCipher: CCDataCipher?, snapshotPublisher: SnapshotPublisher, flowSessionManager: SDLFlowSessionManager) { self.networkAddress = networkAddress self.dataCipher = dataCipher self.snapshotPublisher = snapshotPublisher self.flowSessionManager = flowSessionManager } func makeProcessingPlan(data: SDLData) throws -> ProcessingPlan? { guard let dataCipher = self.dataCipher else { return nil } let mac = LayerPacket.MacAddress(data: data.dstMac) guard (data.dstMac == self.networkAddress.mac || mac.isBroadcast() || mac.isMulticast()) else { return nil } let decryptedData = try dataCipher.decrypt(cipherText: Data(data.data)) let layerPacket = try LayerPacket(layerData: decryptedData) let inboundBytes = decryptedData.count // 处理arp请求 switch layerPacket.type { case .arp: return self.makeARPPlan(layerData: layerPacket.data, inboundBytes: inboundBytes) case .ipv4: return self.makeIPv4Plan(layerData: layerPacket.data, identityID: data.identityID, inboundBytes: inboundBytes) default: SDLLogger.log("[SDLContext] get invalid packet", for: .debug) return .init(inboundBytes: inboundBytes, action: .none) } } private func makeARPPlan(layerData: Data, inboundBytes: Int) -> ProcessingPlan { // 判断如果收到的是arp请求 if let arpPacket = ARPPacket(data: layerData) { if arpPacket.targetIP == self.networkAddress.ip { switch arpPacket.opcode { case .request: let response = ARPPacket.arpResponse(for: arpPacket, mac: self.networkAddress.mac, ip: self.networkAddress.ip) return .init( inboundBytes: inboundBytes, action: .sendARPReply(dstMac: arpPacket.senderMAC, data: response.marshal()) ) case .response: return .init( inboundBytes: inboundBytes, action: .appendARP(ip: arpPacket.senderIP, mac: arpPacket.senderMAC) ) } } else { SDLLogger.log("[SDLContext] get invalid arp packet: \(arpPacket), target_ip: \(SDLUtil.int32ToIp(arpPacket.targetIP)), net ip: \(SDLUtil.int32ToIp(self.networkAddress.ip))") } } else { SDLLogger.log("[SDLContext] get invalid arp packet") } return .init(inboundBytes: inboundBytes, action: .none) } private func makeIPv4Plan(layerData: Data, identityID: UInt32, inboundBytes: Int) -> ProcessingPlan { // 有数据是通过出口网关转发的,所有只判断是合法的ip包 guard let ipPacket = IPPacket(layerData) else { return .init(inboundBytes: inboundBytes, action: .none) } // 检查权限逻辑 let identitySnapshot = self.snapshotPublisher.current() let ruleMap = identitySnapshot.lookup(identityID) if true || self.checkPolicy(ipPacket: ipPacket, ruleMap: ruleMap) { return .init( inboundBytes: inboundBytes, action: .writeToTun(packetData: ipPacket.data, identityID: identityID) ) } return .init( inboundBytes: inboundBytes, action: .requestPolicy(srcIdentityID: identityID) ) } private func checkPolicy(ipPacket: IPPacket, ruleMap: IdentityRuleMap?) -> Bool { // 进来的数据反转一下,然后再处理 if let reverseFlowSession = ipPacket.flowSession()?.reverse(), self.flowSessionManager.hasSession(reverseFlowSession) { self.flowSessionManager.updateSession(reverseFlowSession) return true } // 检查权限逻辑 let proto = ipPacket.header.proto // 优先判断访问规则 switch ipPacket.transportPacket { case .tcp(let tcpPacket): if let ruleMap, ruleMap.isAllow(proto: proto, port: tcpPacket.header.dstPort) { return true } case .udp(let udpPacket): if let ruleMap, ruleMap.isAllow(proto: proto, port: udpPacket.dstPort) { return true } case .icmp(_): return true default: return false } return false } }