fix router
This commit is contained in:
parent
5ce8468959
commit
f72a9acf24
@ -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解析的, dns查询必然是udp包
|
||||
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())")
|
||||
// 查找arp缓存中是否有目标mac地址
|
||||
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)
|
||||
}
|
||||
}
|
||||
// 通过本地的dns解析,发送的是udp的payload部分
|
||||
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) {
|
||||
// 查找arp缓存中是否有目标mac地址
|
||||
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())")
|
||||
// 查找arp缓存中是否有目标mac地址
|
||||
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)
|
||||
}
|
||||
|
||||
// 查找arp缓存中是否有目标mac地址
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
114
Tun/Punchnet/Actors/SDLTunPacketRouter.swift
Normal file
114
Tun/Punchnet/Actors/SDLTunPacketRouter.swift
Normal 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解析的, dns查询必然是udp包
|
||||
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)
|
||||
}
|
||||
|
||||
// 通过本地的dns解析,发送的是udp的payload部分
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user