This commit is contained in:
anlicheng 2026-04-14 21:03:25 +08:00
parent bc87d23ec2
commit 75d7761896
2 changed files with 173 additions and 83 deletions

View File

@ -832,94 +832,41 @@ extension SDLContextActor {
}
}
private func makeHoleDataProcessor() -> SDLHoleDataProcessor {
return .init(
networkAddress: self.config.networkAddress,
dataCipher: self.dataCipher,
snapshotPublisher: self.snapshotPublisher,
flowSessionManager: self.flowSessionManager
)
}
private func handleHoleData(data: SDLData) async throws {
guard let dataCipher = self.dataCipher else {
let processor = self.makeHoleDataProcessor()
guard let plan = try processor.makeProcessingPlan(data: data) else {
return
}
let mac = LayerPacket.MacAddress(data: data.dstMac)
let networkAddr = config.networkAddress
guard (data.dstMac == networkAddr.mac || mac.isBroadcast() || mac.isMulticast()) else {
return
}
self.flowTracer.inc(num: plan.inboundBytes, type: .inbound)
let decyptedData = try dataCipher.decrypt(cipherText: Data(data.data))
let layerPacket = try LayerPacket(layerData: decyptedData)
self.flowTracer.inc(num: decyptedData.count, type: .inbound)
// arp
switch layerPacket.type {
case .arp:
// arp
if let arpPacket = ARPPacket(data: layerPacket.data) {
if arpPacket.targetIP == networkAddr.ip {
switch arpPacket.opcode {
case .request:
switch plan.action {
case .sendARPReply(let dstMac, let responseData):
SDLLogger.log("[SDLContext] get arp request packet")
let response = ARPPacket.arpResponse(for: arpPacket, mac: networkAddr.mac, ip: networkAddr.ip)
await self.routeLayerPacket(dstMac: arpPacket.senderMAC, type: .arp, data: response.marshal())
case .response:
await self.routeLayerPacket(dstMac: dstMac, type: .arp, data: responseData)
case .appendARP(let ip, let mac):
SDLLogger.log("[SDLContext] get arp response packet")
await self.arpServer.append(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(networkAddr.ip))")
}
} else {
SDLLogger.log("[SDLContext] get invalid arp packet")
}
case .ipv4:
// ip
guard let ipPacket = IPPacket(layerPacket.data) else {
return
}
//
let identitySnapshot = self.snapshotPublisher.current()
let ruleMap = identitySnapshot.lookup(data.identityID)
if true || self.checkPolicy(ipPacket: ipPacket, ruleMap: ruleMap) {
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
await self.arpServer.append(ip: ip, mac: mac)
case .writeToTun(let packetData, let identityID):
let packet = NEPacket(data: packetData, protocolFamily: 2)
self.provider.packetFlow.writePacketObjects([packet])
SDLLogger.log("[SDLContext] hole identity: \(data.identityID), allow, data count: \(ipPacket.data.count)", for: .trace)
}
else {
SDLLogger.log("[SDLContext] not found identity: \(data.identityID) ruleMap", for: .debug)
SDLLogger.log("[SDLContext] hole identity: \(identityID), allow, data count: \(packetData.count)", for: .trace)
case .requestPolicy(let srcIdentityID):
SDLLogger.log("[SDLContext] not found identity: \(srcIdentityID) ruleMap", for: .debug)
//
await self.identifyStore.policyRequest(srcIdentityId: data.identityID, dstIdentityId: self.config.identityId, using: self.quicClient)
await self.identifyStore.policyRequest(srcIdentityId: srcIdentityID, dstIdentityId: self.config.identityId, using: self.quicClient)
case .none:
()
}
default:
SDLLogger.log("[SDLContext] get invalid packet", for: .debug)
}
}
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
}
}

View File

@ -0,0 +1,143 @@
//
// 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<IdentitySnapshot>
private let flowSessionManager: SDLFlowSessionManager
init(networkAddress: SDLConfiguration.NetworkAddress,
dataCipher: CCDataCipher?,
snapshotPublisher: SnapshotPublisher<IdentitySnapshot>,
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
}
}