punchnet-macos/Tun/Punchnet/Inbound/SDLHoleDataProcessor.swift
2026-05-20 21:55:58 +08:00

121 lines
4.6 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.

//
// 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 policySnapshot: PolicySnapshot
private let flowSessionManager: SDLFlowSessionManager
init(networkAddress: SDLConfiguration.NetworkAddress,
dataCipher: CCDataCipher?,
policySnapshot: PolicySnapshot,
flowSessionManager: SDLFlowSessionManager) {
self.networkAddress = networkAddress
self.dataCipher = dataCipher
self.policySnapshot = policySnapshot
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)
}
if let reverseFlowSession = ipPacket.flowSession()?.reverse(),
self.flowSessionManager.hasSession(reverseFlowSession) {
self.flowSessionManager.updateSession(reverseFlowSession)
return .init(
inboundBytes: inboundBytes,
action: .writeToTun(packetData: ipPacket.data, identityID: identityID)
)
}
//
if self.policySnapshot.allows(srcIdentityID: identityID, ipPacket: ipPacket) {
return .init(
inboundBytes: inboundBytes,
action: .writeToTun(packetData: ipPacket.data, identityID: identityID)
)
}
return .init(
inboundBytes: inboundBytes,
action: .requestPolicy(srcIdentityID: identityID)
)
}
}