diff --git a/Tun/Inbound/PacketInboundActor.swift b/Tun/Inbound/PacketInboundActor.swift index 59a7825..af46777 100644 --- a/Tun/Inbound/PacketInboundActor.swift +++ b/Tun/Inbound/PacketInboundActor.swift @@ -9,6 +9,35 @@ import Foundation import NetworkExtension actor PacketInboundActor { + private struct PolicyPacketContext { + let srcIdentityID: UInt32 + let proto: UInt8 + let srcIP: UInt32 + let dstIP: UInt32 + let srcPort: UInt16? + let dstPort: UInt16? + + var logDescription: String { + let srcPort = self.srcPort.map(String.init) ?? "-" + let dstPort = self.dstPort.map(String.init) ?? "-" + return "srcIdentityID: \(self.srcIdentityID), proto: \(self.proto), srcIP: \(SDLUtil.int32ToIp(self.srcIP)), dstIP: \(SDLUtil.int32ToIp(self.dstIP)), srcPort: \(srcPort), dstPort: \(dstPort)" + } + } + + private enum ProcessingAction { + case sendARPReply(dstMac: Data, data: Data) + case appendARP(ip: UInt32, mac: Data) + case writeToTun(packetData: Data, identityID: UInt32) + case requestPolicy(PolicyPacketContext) + case dropByPolicy(PolicyPacketContext) + case none + } + + private struct ProcessingPlan { + let inboundBytes: Int + let action: ProcessingAction + } + private let provider: NEPacketTunnelProvider private let policyService: PolicyService private let packetOutboundActor: PacketOutboundActor @@ -46,13 +75,8 @@ actor PacketInboundActor { } func handleData(_ data: SDLData) async { - let processor = PacketInboundProcessor( - networkAddress: self.networkAddress, - dataCipher: self.dataCipher, - policyRuntime: self.policyService.policyRuntime() - ) - - guard let plan = try? processor.makeProcessingPlan(data: data) else { + let policyRuntime = self.policyService.policyRuntime() + guard let plan = try? self.makeProcessingPlan(data: data, policyRuntime: policyRuntime) else { return } @@ -80,4 +104,105 @@ actor PacketInboundActor { () } } + + private func makeProcessingPlan(data: SDLData, policyRuntime: PolicyRuntime) 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) + let layerPacket = try LayerPacketView(layerData: decryptedData) + let inboundBytes = decryptedData.count + + 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, + policyRuntime: policyRuntime + ) + default: + SDLLogger.log("[SDLContext] get invalid packet", for: .debug) + return .init(inboundBytes: inboundBytes, action: .none) + } + } + + private func makeARPPlan(layerData: Data, inboundBytes: Int) -> ProcessingPlan { + 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, policyRuntime: PolicyRuntime) -> ProcessingPlan { + guard let ipPacket = IPPacket(layerData) else { + return .init(inboundBytes: inboundBytes, action: .none) + } + + switch policyRuntime.evaluateInbound(srcIdentityID: identityID, ipPacket: ipPacket) { + case .allow: + return .init( + inboundBytes: inboundBytes, + action: .writeToTun(packetData: ipPacket.data, identityID: identityID) + ) + case .deny: + return .init( + inboundBytes: inboundBytes, + action: .dropByPolicy(self.makePolicyPacketContext(identityID: identityID, ipPacket: ipPacket)) + ) + case .missingPolicy: + return .init( + inboundBytes: inboundBytes, + action: .requestPolicy(self.makePolicyPacketContext(identityID: identityID, ipPacket: ipPacket)) + ) + } + } + + private func makePolicyPacketContext(identityID: UInt32, ipPacket: IPPacket) -> PolicyPacketContext { + let ports: (UInt16?, UInt16?) + switch ipPacket.transportPacket { + case .tcp(let tcpPacket): + ports = (tcpPacket.header.srcPort, tcpPacket.header.dstPort) + case .udp(let udpPacket): + ports = (udpPacket.srcPort, udpPacket.dstPort) + default: + ports = (nil, nil) + } + + return PolicyPacketContext( + srcIdentityID: identityID, + proto: ipPacket.header.proto, + srcIP: ipPacket.header.source, + dstIP: ipPacket.header.destination, + srcPort: ports.0, + dstPort: ports.1 + ) + } } diff --git a/Tun/Inbound/PacketInboundProcessor.swift b/Tun/Inbound/PacketInboundProcessor.swift deleted file mode 100644 index ede0de4..0000000 --- a/Tun/Inbound/PacketInboundProcessor.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// PacketInboundProcessor.swift -// Tun -// -// Created by 安礼成 on 2026/4/14. -// - -import Foundation - -final class PacketInboundProcessor { - struct PolicyPacketContext { - let srcIdentityID: UInt32 - let proto: UInt8 - let srcIP: UInt32 - let dstIP: UInt32 - let srcPort: UInt16? - let dstPort: UInt16? - - var logDescription: String { - let srcPort = self.srcPort.map(String.init) ?? "-" - let dstPort = self.dstPort.map(String.init) ?? "-" - return "srcIdentityID: \(self.srcIdentityID), proto: \(self.proto), srcIP: \(SDLUtil.int32ToIp(self.srcIP)), dstIP: \(SDLUtil.int32ToIp(self.dstIP)), srcPort: \(srcPort), dstPort: \(dstPort)" - } - } - - enum ProcessingAction { - case sendARPReply(dstMac: Data, data: Data) - case appendARP(ip: UInt32, mac: Data) - case writeToTun(packetData: Data, identityID: UInt32) - case requestPolicy(PolicyPacketContext) - case dropByPolicy(PolicyPacketContext) - case none - } - - struct ProcessingPlan { - let inboundBytes: Int - let action: ProcessingAction - } - - private let networkAddress: SDLConfiguration.NetworkAddress - private let dataCipher: CCDataCipher? - private let policyRuntime: PolicyRuntime - - init(networkAddress: SDLConfiguration.NetworkAddress, - dataCipher: CCDataCipher?, - policyRuntime: PolicyRuntime) { - self.networkAddress = networkAddress - self.dataCipher = dataCipher - self.policyRuntime = policyRuntime - } - - 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) - let layerPacket = try LayerPacketView(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) - } - - switch self.policyRuntime.evaluateInbound(srcIdentityID: identityID, ipPacket: ipPacket) { - case .allow: - return .init( - inboundBytes: inboundBytes, - action: .writeToTun(packetData: ipPacket.data, identityID: identityID) - ) - case .deny: - return .init( - inboundBytes: inboundBytes, - action: .dropByPolicy(self.makePolicyPacketContext(identityID: identityID, ipPacket: ipPacket)) - ) - case .missingPolicy: - return .init( - inboundBytes: inboundBytes, - action: .requestPolicy(self.makePolicyPacketContext(identityID: identityID, ipPacket: ipPacket)) - ) - } - } - - private func makePolicyPacketContext(identityID: UInt32, ipPacket: IPPacket) -> PolicyPacketContext { - let ports: (UInt16?, UInt16?) - switch ipPacket.transportPacket { - case .tcp(let tcpPacket): - ports = (tcpPacket.header.srcPort, tcpPacket.header.dstPort) - case .udp(let udpPacket): - ports = (udpPacket.srcPort, udpPacket.dstPort) - default: - ports = (nil, nil) - } - - return PolicyPacketContext( - srcIdentityID: identityID, - proto: ipPacket.header.proto, - srcIP: ipPacket.header.source, - dstIP: ipPacket.header.destination, - srcPort: ports.0, - dstPort: ports.1 - ) - } -}