fix router

This commit is contained in:
anlicheng 2026-04-14 20:07:17 +08:00
parent 5ce8468959
commit f72a9acf24
2 changed files with 221 additions and 135 deletions

View File

@ -748,141 +748,6 @@ actor SDLContextActor {
}
}
// , Tun
private func dealTunPacket(packet: IPPacket) async {
let networkAddr = self.config.networkAddress
let dstIp = packet.header.destination
// , ip
if dstIp == networkAddr.ip {
let nePacket = NEPacket(data: packet.data, protocolFamily: 2)
self.provider.packetFlow.writePacketObjects([nePacket])
}
// dns
else if DNSHelper.isDnsRequestPacket(ipPacket: packet) {
if case .udp(let udpPacket) = packet.transportPacket {
// offset, dnsudp
let payloadOffset = udpPacket.payloadOffset
let dnsParser = DNSParser(data: packet.data, offset: payloadOffset)
if let dnsMessage = dnsParser.parse(), let name = dnsMessage.questions.first?.name {
// ip
if name.contains(self.config.networkAddress.networkDomain) {
SDLLogger.log("[SDLContext] get cloud dns request: \(name)")
if let dnsClient = self.dnsClient {
await dnsClient.forward(ipPacketData: packet.data)
}
}
//
else if let exitNode = config.exitNode {
let exitNodeIp = exitNode.exitNodeIp
SDLLogger.log("[SDLContext] dstIp: \(packet.header.destination.asIpAddress()), use exit_node: \(exitNodeIp.asIpAddress())")
// arpmac
if let dstMac = await self.arpServer.query(ip: exitNodeIp) {
await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data)
}
else {
try? await self.arpServer.arpRequest(targetIp: exitNodeIp, use: self.quicClient)
}
}
// dnsudppayload
else {
SDLLogger.log("[SDLContext] get local dns request: \(name)")
let dnsPayload = Data(packet.data[payloadOffset..<packet.data.count])
let tracker = DNSLocalClient.DNSTracker(transactionID: dnsMessage.transactionID,
clientIP: packet.header.source,
clientPort: udpPacket.srcPort,
createdAt: Date())
if let dnsLocalClient = self.dnsLocalClient {
await dnsLocalClient.query(tracker: tracker, dnsPayload: dnsPayload)
}
}
}
}
}
else {
// FlowSession
//
if let flowSession = packet.flowSession() {
self.flowSessionManager.updateSession(flowSession)
//SDLLogger.shared.log("[SDLContext] flow_session: \(flowSession)", level: .debug)
}
//
// ip
if SDLUtil.inSameNetwork(ip: dstIp, compareIp: networkAddr.ip, maskLen: networkAddr.maskLen) {
// arpmac
if let dstMac = await self.arpServer.query(ip: dstIp) {
SDLLogger.log("[SDLContext] dstIp: \(dstIp.asIpAddress()), dst_mac is: \(SDLUtil.formatMacAddress(mac: dstMac))", for: .trace)
await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data)
}
else {
SDLLogger.log("[SDLContext] dstIp: \(dstIp.asIpAddress()) arp query not found, broadcast", for: .trace)
// // arp广
// let arpReqeust = ARPPacket.arpRequest(senderIP: networkAddr.ip, senderMAC: networkAddr.mac, targetIP: dstIp)
// await self.routeLayerPacket(dstMac: ARPPacket.broadcastMac , type: .arp, data: arpReqeust.marshal())
try? await self.arpServer.arpRequest(targetIp: dstIp, use: self.quicClient)
}
}
// ,
else if let exitNode = config.exitNode {
let exitNodeIp: UInt32 = exitNode.exitNodeIp
SDLLogger.log("[SDLContext] dstIp: \(packet.header.destination.asIpAddress()), use exit_node: \(exitNodeIp.asIpAddress())")
// arpmac
if let dstMac = await self.arpServer.query(ip: exitNodeIp) {
await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data)
}
else {
try? await self.arpServer.arpRequest(targetIp: exitNodeIp, use: self.quicClient)
}
}
}
}
private func routeLayerPacket(dstMac: Data, type: LayerPacket.PacketType, data: Data) async {
let networkAddr = self.config.networkAddress
// 2
let layerPacket = LayerPacket(dstMac: dstMac, srcMac: networkAddr.mac, type: type, data: data)
guard let dataCipher = self.dataCipher,
let encodedPacket = try? dataCipher.encrypt(plainText: layerPacket.marshal()) else {
return
}
//
var dataPacket = SDLData()
dataPacket.networkID = networkAddr.networkId
dataPacket.srcMac = networkAddr.mac
dataPacket.dstMac = dstMac
dataPacket.ttl = 255
dataPacket.identityID = self.config.identityId
dataPacket.data = encodedPacket
let data = try! dataPacket.serializedData()
// 广
if ARPPacket.isBroadcastMac(dstMac) {
// super_node
self.sendSuperPacket(type: .data, data: data)
}
else {
// session
if let session = self.sessionManager.getSession(toAddress: dstMac) {
SDLLogger.log("[SDLContext] step 5 send packet by session: \(session)", for: .trace)
self.sendPeerPacket(type: .data, data: data, remoteAddress: session.natAddress)
self.flowTracer.inc(num: data.count, type: .p2p)
}
else {
// super_node
self.sendSuperPacket(type: .data, data: data)
SDLLogger.log("[SDLContext] step 5 send packet by super: \(self.config.stunSocketAddress)", for: .trace)
//
self.flowTracer.inc(num: data.count, type: .forward)
//
await self.puncherActor.submitRegisterRequest(quicClient: self.quicClient, request: .init(srcMac: networkAddr.mac, dstMac: dstMac, networkId: networkAddr.networkId))
}
}
}
// MARK:
private func setNetworkSettings(config: SDLConfiguration, dnsServer: String) async throws {
let networkAddress = config.networkAddress
@ -1052,3 +917,110 @@ private extension UInt32 {
return SDLUtil.int32ToIp(self)
}
}
// Tun
extension SDLContextActor {
// , Tun
private func dealTunPacket(packet: IPPacket) async {
let router = SDLTunPacketRouter(networkAddress: self.config.networkAddress, exitNode: self.config.exitNode)
let decision = router.route(packet: packet)
// FlowSession
//
if decision.shouldTrackFlow, let flowSession = packet.flowSession() {
self.flowSessionManager.updateSession(flowSession)
//SDLLogger.shared.log("[SDLContext] flow_session: \(flowSession)", level: .debug)
}
await self.handleTunRouteDecision(decision)
}
private func handleTunRouteDecision(_ decision: SDLTunPacketRouter.RouteDecision) async {
switch decision {
case .loopback(let ipPacketData):
let nePacket = NEPacket(data: ipPacketData, protocolFamily: 2)
self.provider.packetFlow.writePacketObjects([nePacket])
case .cloudDNS(let name, let ipPacketData):
SDLLogger.log("[SDLContext] get cloud dns request: \(name)")
await self.dnsClient?.forward(ipPacketData: ipPacketData)
case .localDNS(let name, let payload, let tracker):
SDLLogger.log("[SDLContext] get local dns request: \(name)")
await self.dnsLocalClient?.query(tracker: tracker, dnsPayload: payload)
case .forwardToNextHop(let ip, let type, let data, let kind):
await self.forwardPacketToNextHop(ip: ip, type: type, data: data, kind: kind)
case .drop(let reason):
SDLLogger.log("[SDLContext] drop tun packet, reason: \(reason.rawValue)", for: .trace)
}
}
private func forwardPacketToNextHop(ip: UInt32, type: LayerPacket.PacketType, data: Data, kind: SDLTunPacketRouter.ForwardKind) async {
switch kind {
case .sameNetwork:
SDLLogger.log("[SDLContext] dstIp: \(ip.asIpAddress()) same network", for: .trace)
case .exitNode, .dnsExitNode:
SDLLogger.log("[SDLContext] use exit_node: \(ip.asIpAddress())", for: .trace)
}
// arpmac
if let dstMac = await self.arpServer.query(ip: ip) {
SDLLogger.log("[SDLContext] dstIp: \(ip.asIpAddress()), dst_mac is: \(SDLUtil.formatMacAddress(mac: dstMac))", for: .trace)
await self.routeLayerPacket(dstMac: dstMac, type: type, data: data)
}
else {
SDLLogger.log("[SDLContext] dstIp: \(ip.asIpAddress()) arp query not found, broadcast", for: .trace)
// // arp广
// let arpReqeust = ARPPacket.arpRequest(senderIP: networkAddr.ip, senderMAC: networkAddr.mac, targetIP: dstIp)
// await self.routeLayerPacket(dstMac: ARPPacket.broadcastMac , type: .arp, data: arpReqeust.marshal())
try? await self.arpServer.arpRequest(targetIp: ip, use: self.quicClient)
}
}
private func routeLayerPacket(dstMac: Data, type: LayerPacket.PacketType, data: Data) async {
let networkAddr = self.config.networkAddress
// 2
let layerPacket = LayerPacket(dstMac: dstMac, srcMac: networkAddr.mac, type: type, data: data)
guard let dataCipher = self.dataCipher,
let encodedPacket = try? dataCipher.encrypt(plainText: layerPacket.marshal()) else {
return
}
//
var dataPacket = SDLData()
dataPacket.networkID = networkAddr.networkId
dataPacket.srcMac = networkAddr.mac
dataPacket.dstMac = dstMac
dataPacket.ttl = 255
dataPacket.identityID = self.config.identityId
dataPacket.data = encodedPacket
let data = try! dataPacket.serializedData()
// 广
if ARPPacket.isBroadcastMac(dstMac) {
// super_node
self.sendSuperPacket(type: .data, data: data)
}
else {
// session
if let session = self.sessionManager.getSession(toAddress: dstMac) {
SDLLogger.log("[SDLContext] step 5 send packet by session: \(session)", for: .trace)
self.sendPeerPacket(type: .data, data: data, remoteAddress: session.natAddress)
self.flowTracer.inc(num: data.count, type: .p2p)
}
else {
// super_node
self.sendSuperPacket(type: .data, data: data)
SDLLogger.log("[SDLContext] step 5 send packet by super: \(self.config.stunSocketAddress)", for: .trace)
//
self.flowTracer.inc(num: data.count, type: .forward)
//
await self.puncherActor.submitRegisterRequest(quicClient: self.quicClient, request: .init(srcMac: networkAddr.mac, dstMac: dstMac, networkId: networkAddr.networkId))
}
}
}
}

View File

@ -0,0 +1,114 @@
//
// SDLTunPacketRouter.swift
// Tun
//
// Created by on 2026/4/14.
//
import Foundation
struct SDLTunPacketRouter {
enum DropReason: String {
case invalidDNSRequest
case noRoute
}
enum ForwardKind {
case sameNetwork
case exitNode
case dnsExitNode
}
enum RouteDecision {
case loopback(ipPacketData: Data)
case cloudDNS(name: String, ipPacketData: Data)
case localDNS(name: String, payload: Data, tracker: DNSLocalClient.DNSTracker)
case forwardToNextHop(ip: UInt32, type: LayerPacket.PacketType, data: Data, kind: ForwardKind)
case drop(reason: DropReason)
}
let networkAddress: SDLConfiguration.NetworkAddress
let exitNode: SDLConfiguration.ExitNode?
func route(packet: IPPacket, now: Date = Date()) -> RouteDecision {
let dstIp = packet.header.destination
// , ip
if dstIp == self.networkAddress.ip {
return .loopback(ipPacketData: packet.data)
}
// dns
if let dnsDecision = self.routeDNS(packet: packet, now: now) {
return dnsDecision
}
//
// ip
if SDLUtil.inSameNetwork(ip: dstIp, compareIp: self.networkAddress.ip, maskLen: self.networkAddress.maskLen) {
return .forwardToNextHop(ip: dstIp, type: .ipv4, data: packet.data, kind: .sameNetwork)
}
// ,
if let exitNode = self.exitNode {
return .forwardToNextHop(ip: exitNode.exitNodeIp, type: .ipv4, data: packet.data, kind: .exitNode)
}
return .drop(reason: .noRoute)
}
private func routeDNS(packet: IPPacket, now: Date) -> RouteDecision? {
guard DNSHelper.isDnsRequestPacket(ipPacket: packet) else {
return nil
}
guard case .udp(let udpPacket) = packet.transportPacket else {
return .drop(reason: .invalidDNSRequest)
}
// offset, dnsudp
let payloadOffset = udpPacket.payloadOffset
let dnsParser = DNSParser(data: packet.data, offset: payloadOffset)
guard let dnsMessage = dnsParser.parse(), let name = dnsMessage.questions.first?.name else {
return .drop(reason: .invalidDNSRequest)
}
// ip
if name.contains(self.networkAddress.networkDomain) {
return .cloudDNS(name: name, ipPacketData: packet.data)
}
//
if let exitNode = self.exitNode {
return .forwardToNextHop(ip: exitNode.exitNodeIp, type: .ipv4, data: packet.data, kind: .dnsExitNode)
}
// dnsudppayload
let dnsPayload = Data(packet.data[payloadOffset..<packet.data.count])
let tracker = DNSLocalClient.DNSTracker(
transactionID: dnsMessage.transactionID,
clientIP: packet.header.source,
clientPort: udpPacket.srcPort,
createdAt: now
)
return .localDNS(name: name, payload: dnsPayload, tracker: tracker)
}
}
extension SDLTunPacketRouter.RouteDecision {
var shouldTrackFlow: Bool {
switch self {
case .forwardToNextHop(_, _, _, let kind):
switch kind {
case .sameNetwork, .exitNode:
return true
case .dnsExitNode:
return false
}
default:
return false
}
}
}