fix holeControlPlane
This commit is contained in:
parent
eca022cae0
commit
1907c4347b
@ -30,6 +30,7 @@ actor SDLContextActor {
|
|||||||
private let dnsLocalService: DNSLocalService
|
private let dnsLocalService: DNSLocalService
|
||||||
private let superService: SDLSuperService
|
private let superService: SDLSuperService
|
||||||
private let superControlPlane: SDLSuperControlPlane
|
private let superControlPlane: SDLSuperControlPlane
|
||||||
|
private let holeControlPlane: SDLHoleControlPlane
|
||||||
private let udpHoleService: SDLUDPHoleService
|
private let udpHoleService: SDLUDPHoleService
|
||||||
private let udpHoleV6Service: SDLUDPHoleV6Service
|
private let udpHoleV6Service: SDLUDPHoleV6Service
|
||||||
private let packetOutboundActor: PacketOutboundActor
|
private let packetOutboundActor: PacketOutboundActor
|
||||||
@ -76,6 +77,7 @@ actor SDLContextActor {
|
|||||||
let dnsCloudService = DNSCloudService(serverIP: config.serverEndpoint.ip)
|
let dnsCloudService = DNSCloudService(serverIP: config.serverEndpoint.ip)
|
||||||
let dnsLocalService = DNSLocalService(publicDnsServers: Self.publicDnsServers)
|
let dnsLocalService = DNSLocalService(publicDnsServers: Self.publicDnsServers)
|
||||||
let superControlPlane = SDLSuperControlPlane(config: config, rsaCipher: rsaCipher)
|
let superControlPlane = SDLSuperControlPlane(config: config, rsaCipher: rsaCipher)
|
||||||
|
let holeControlPlane = SDLHoleControlPlane(networkAddress: config.networkAddress)
|
||||||
let tunNetworkManager = SDLTunNetworkManager(provider: provider)
|
let tunNetworkManager = SDLTunNetworkManager(provider: provider)
|
||||||
let ipv6AssistPair = AsyncStream.makeStream(of: Optional<SDLV6Info>.self, bufferingPolicy: .bufferingNewest(1))
|
let ipv6AssistPair = AsyncStream.makeStream(of: Optional<SDLV6Info>.self, bufferingPolicy: .bufferingNewest(1))
|
||||||
let packetOutboundActor = PacketOutboundActor(
|
let packetOutboundActor = PacketOutboundActor(
|
||||||
@ -122,6 +124,7 @@ actor SDLContextActor {
|
|||||||
self.dnsLocalService = dnsLocalService
|
self.dnsLocalService = dnsLocalService
|
||||||
self.superService = superService
|
self.superService = superService
|
||||||
self.superControlPlane = superControlPlane
|
self.superControlPlane = superControlPlane
|
||||||
|
self.holeControlPlane = holeControlPlane
|
||||||
self.udpHoleService = udpHoleService
|
self.udpHoleService = udpHoleService
|
||||||
self.udpHoleV6Service = udpHoleV6Service
|
self.udpHoleV6Service = udpHoleV6Service
|
||||||
self.packetOutboundActor = packetOutboundActor
|
self.packetOutboundActor = packetOutboundActor
|
||||||
@ -410,16 +413,15 @@ actor SDLContextActor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: probe网络类型
|
|
||||||
extension SDLContextActor {
|
extension SDLContextActor {
|
||||||
|
|
||||||
|
// MARK: probe网络类型
|
||||||
|
|
||||||
private func setNatType(natType: SDLNATProberActor.NatType) {
|
private func setNatType(natType: SDLNATProberActor.NatType) {
|
||||||
self.natType = natType
|
self.natType = natType
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Notifier通知机制
|
// MARK: Notifier通知机制
|
||||||
extension SDLContextActor {
|
|
||||||
|
|
||||||
private func prepareTunnelNotifier() {
|
private func prepareTunnelNotifier() {
|
||||||
// 启动noticeClient
|
// 启动noticeClient
|
||||||
@ -432,15 +434,8 @@ extension SDLContextActor {
|
|||||||
private func publishTunnelEvent(code: Int? = nil, message: String) {
|
private func publishTunnelEvent(code: Int? = nil, message: String) {
|
||||||
SDLTunnelAppNotifier.shared.publish(code: code, message: message)
|
SDLTunnelAppNotifier.shared.publish(code: code, message: message)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: 数据发送
|
// MARK: 数据发送
|
||||||
extension SDLContextActor {
|
|
||||||
|
|
||||||
// 发送给peer的数据
|
|
||||||
private func sendPeerPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async {
|
|
||||||
await self.sendPacket(type: type, data: data, remoteAddress: remoteAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func sendPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async {
|
private func sendPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async {
|
||||||
switch remoteAddress {
|
switch remoteAddress {
|
||||||
@ -452,10 +447,8 @@ extension SDLContextActor {
|
|||||||
SDLLogger.log("[SDLContext] unsupported socket family: \(remoteAddress)", for: .debug)
|
SDLLogger.log("[SDLContext] unsupported socket family: \(remoteAddress)", for: .debug)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: 处理和Super之间的通讯
|
// MARK: 处理和Super之间的通讯
|
||||||
extension SDLContextActor {
|
|
||||||
|
|
||||||
private func handleSuperDecision(_ decision: SuperDecision) async {
|
private func handleSuperDecision(_ decision: SuperDecision) async {
|
||||||
switch decision {
|
switch decision {
|
||||||
@ -530,10 +523,8 @@ extension SDLContextActor {
|
|||||||
self.config.acl = acl
|
self.config.acl = acl
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// MARK: DNS service events
|
||||||
|
|
||||||
// MARK: DNS service events
|
|
||||||
extension SDLContextActor {
|
|
||||||
private func handleDNSEvent(_ event: DNSEvent) async {
|
private func handleDNSEvent(_ event: DNSEvent) async {
|
||||||
switch event {
|
switch event {
|
||||||
case .packet(let packet):
|
case .packet(let packet):
|
||||||
@ -541,91 +532,29 @@ extension SDLContextActor {
|
|||||||
self.provider.packetFlow.writePacketObjects([nePacket])
|
self.provider.packetFlow.writePacketObjects([nePacket])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: 处理从Hole收到的数据
|
// MARK: 处理从Hole收到的数据
|
||||||
extension SDLContextActor {
|
|
||||||
|
|
||||||
private func handleUDPHoleControlEvent(_ event: SDLUDPHoleService.Event) async {
|
private func handleUDPHoleControlEvent(_ event: SDLUDPHoleService.Event) async {
|
||||||
switch event {
|
let decisions = self.holeControlPlane.handle(event)
|
||||||
case .ready(let localAddress):
|
for decision in decisions {
|
||||||
SDLLogger.log("[SDLContext] udpHole ready: \(localAddress)")
|
await self.handleHoleDecision(decision)
|
||||||
case .natType(let natType):
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleHoleDecision(_ decision: HoleDecision) async {
|
||||||
|
switch decision {
|
||||||
|
case .updateNatType(let natType):
|
||||||
self.setNatType(natType: natType)
|
self.setNatType(natType: natType)
|
||||||
SDLLogger.log("[SDLContext] nat_type is: \(natType)")
|
case .sendPacket(let type, let data, let remoteAddress):
|
||||||
case .packet(let remoteAddress, let message):
|
await self.sendPacket(type: type, data: data, remoteAddress: remoteAddress)
|
||||||
await self.handleUDPHolePacket(remoteAddress: remoteAddress, message: message)
|
case .addSession(let session):
|
||||||
case .closed(let error):
|
await self.sessionManager.addSession(session: session)
|
||||||
SDLLogger.log("[SDLContext] udpHole closed: \(error)", for: .debug)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleUDPHolePacket(remoteAddress: SocketAddress, message: SDLHoleControlMessage) async {
|
// MARK: 和Stun相关的心跳机制
|
||||||
switch message {
|
|
||||||
case .stunReply(_), .stunProbeReply(_):
|
|
||||||
SDLLogger.log("[SDLContext] get a stun reply", for: .debug)
|
|
||||||
case .register(let register):
|
|
||||||
try? await self.handleRegister(remoteAddress: remoteAddress, register: register)
|
|
||||||
case .registerAck(let registerAck):
|
|
||||||
await self.handleRegisterAck(remoteAddress: remoteAddress, registerAck: registerAck)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleRegister(remoteAddress: SocketAddress, register: SDLRegister) async throws {
|
|
||||||
let networkAddr = config.networkAddress
|
|
||||||
SDLLogger.log("[SDLContext] register packet: \(register), network_address: \(networkAddr)")
|
|
||||||
|
|
||||||
// 判断目标地址是否是tun的网卡地址, 并且是在同一个网络下
|
|
||||||
if register.dstMac == networkAddr.mac && register.networkID == networkAddr.networkId {
|
|
||||||
// 回复ack包
|
|
||||||
var registerAck = SDLRegisterAck()
|
|
||||||
registerAck.networkID = networkAddr.networkId
|
|
||||||
registerAck.srcMac = networkAddr.mac
|
|
||||||
registerAck.dstMac = register.srcMac
|
|
||||||
|
|
||||||
await self.sendPeerPacket(type: .registerAck, data: try registerAck.serializedData(), remoteAddress: remoteAddress)
|
|
||||||
// 这里需要建立到来源的会话, 在复杂网络下,通过super-node查询到的nat地址不一定靠谱,需要通过udp包的来源地址作为nat地址
|
|
||||||
if let addressType = Self.addressType(from: remoteAddress),
|
|
||||||
let session = Session(dstMac: register.srcMac, natAddress: remoteAddress, addressType: addressType) {
|
|
||||||
await self.sessionManager.addSession(session: session)
|
|
||||||
} else {
|
|
||||||
SDLLogger.log("[SDLContext] didReadRegister get unsupported remoteAddress: \(remoteAddress)", for: .debug)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDLLogger.log("[SDLContext] didReadRegister get a invalid packet, because dst_ip not matched: \(register.dstMac)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleRegisterAck(remoteAddress: SocketAddress, registerAck: SDLRegisterAck) async {
|
|
||||||
// 判断目标地址是否是tun的网卡地址, 并且是在同一个网络下
|
|
||||||
let networkAddr = config.networkAddress
|
|
||||||
if registerAck.dstMac == networkAddr.mac && registerAck.networkID == networkAddr.networkId {
|
|
||||||
if let addressType = Self.addressType(from: remoteAddress),
|
|
||||||
let session = Session(dstMac: registerAck.srcMac, natAddress: remoteAddress, addressType: addressType) {
|
|
||||||
await self.sessionManager.addSession(session: session)
|
|
||||||
} else {
|
|
||||||
SDLLogger.log("[SDLContext] didReadRegisterAck get unsupported remoteAddress: \(remoteAddress)", for: .debug)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDLLogger.log("[SDLContext] didReadRegisterAck get a invalid packet, because dst_mac not matched: \(registerAck.dstMac)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func addressType(from remoteAddress: SocketAddress) -> Session.AddressType? {
|
|
||||||
switch remoteAddress {
|
|
||||||
case .v4:
|
|
||||||
return .v4
|
|
||||||
case .v6:
|
|
||||||
return .v6
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: 和Stun相关的心跳机制
|
|
||||||
extension SDLContextActor {
|
|
||||||
private func runStunRequestOnce() async throws {
|
private func runStunRequestOnce() async throws {
|
||||||
let probeReply = try? await self.ipv6AssistClient?.probe(requestTimeout: .seconds(3))
|
let probeReply = try? await self.ipv6AssistClient?.probe(requestTimeout: .seconds(3))
|
||||||
|
|
||||||
@ -637,10 +566,8 @@ extension SDLContextActor {
|
|||||||
|
|
||||||
await self.superControlPlane.sendStunRequest(natType: self.natType, v6Info: probeReply?.v6Info)
|
await self.superControlPlane.sendStunRequest(natType: self.natType, v6Info: probeReply?.v6Info)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: NEPacketTunnelProvider相关的逻辑
|
// MARK: NEPacketTunnelProvider相关的逻辑
|
||||||
extension SDLContextActor {
|
|
||||||
|
|
||||||
// 取消出口节点的时候,ip地址为: 0.0.0.0
|
// 取消出口节点的时候,ip地址为: 0.0.0.0
|
||||||
public func updateExitNode(exitNodeIp: String) async throws {
|
public func updateExitNode(exitNodeIp: String) async throws {
|
||||||
|
|||||||
113
Tun/Context/SDLHoleControlPlane.swift
Normal file
113
Tun/Context/SDLHoleControlPlane.swift
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//
|
||||||
|
// SDLHoleControlPlane.swift
|
||||||
|
// Tun
|
||||||
|
//
|
||||||
|
// Created by Codex on 2026/5/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
enum HoleDecision {
|
||||||
|
case updateNatType(SDLNATProberActor.NatType)
|
||||||
|
case sendPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress)
|
||||||
|
case addSession(Session)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SDLHoleControlPlane {
|
||||||
|
private let networkAddress: SDLConfiguration.NetworkAddress
|
||||||
|
|
||||||
|
init(networkAddress: SDLConfiguration.NetworkAddress) {
|
||||||
|
self.networkAddress = networkAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle(_ event: SDLUDPHoleService.Event) -> [HoleDecision] {
|
||||||
|
switch event {
|
||||||
|
case .ready(let localAddress):
|
||||||
|
SDLLogger.log("[SDLContext] udpHole ready: \(localAddress)")
|
||||||
|
return []
|
||||||
|
case .natType(let natType):
|
||||||
|
SDLLogger.log("[SDLContext] nat_type is: \(natType)")
|
||||||
|
return [
|
||||||
|
.updateNatType(natType)
|
||||||
|
]
|
||||||
|
case .packet(let remoteAddress, let message):
|
||||||
|
return self.handlePacket(remoteAddress: remoteAddress, message: message)
|
||||||
|
case .closed(let error):
|
||||||
|
SDLLogger.log("[SDLContext] udpHole closed: \(error)", for: .debug)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handlePacket(remoteAddress: SocketAddress, message: SDLHoleControlMessage) -> [HoleDecision] {
|
||||||
|
switch message {
|
||||||
|
case .stunReply, .stunProbeReply:
|
||||||
|
SDLLogger.log("[SDLContext] get a stun reply", for: .debug)
|
||||||
|
return []
|
||||||
|
case .register(let register):
|
||||||
|
return self.handleRegister(remoteAddress: remoteAddress, register: register)
|
||||||
|
case .registerAck(let registerAck):
|
||||||
|
return self.handleRegisterAck(remoteAddress: remoteAddress, registerAck: registerAck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleRegister(remoteAddress: SocketAddress, register: SDLRegister) -> [HoleDecision] {
|
||||||
|
SDLLogger.log("[SDLContext] register packet: \(register), network_address: \(self.networkAddress)")
|
||||||
|
var decisions: [HoleDecision] = []
|
||||||
|
|
||||||
|
guard register.dstMac == self.networkAddress.mac && register.networkID == self.networkAddress.networkId else {
|
||||||
|
SDLLogger.log("[SDLContext] didReadRegister get a invalid packet, because dst_ip not matched: \(register.dstMac)")
|
||||||
|
return decisions
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerAck = SDLRegisterAck()
|
||||||
|
registerAck.networkID = self.networkAddress.networkId
|
||||||
|
registerAck.srcMac = self.networkAddress.mac
|
||||||
|
registerAck.dstMac = register.srcMac
|
||||||
|
|
||||||
|
if let data = try? registerAck.serializedData() {
|
||||||
|
decisions.append(.sendPacket(type: .registerAck, data: data, remoteAddress: remoteAddress))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let session = self.makeSession(dstMac: register.srcMac, remoteAddress: remoteAddress) {
|
||||||
|
decisions.append(.addSession(session))
|
||||||
|
} else {
|
||||||
|
SDLLogger.log("[SDLContext] didReadRegister get unsupported remoteAddress: \(remoteAddress)", for: .debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
return decisions
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleRegisterAck(remoteAddress: SocketAddress, registerAck: SDLRegisterAck) -> [HoleDecision] {
|
||||||
|
guard registerAck.dstMac == self.networkAddress.mac && registerAck.networkID == self.networkAddress.networkId else {
|
||||||
|
SDLLogger.log("[SDLContext] didReadRegisterAck get a invalid packet, because dst_mac not matched: \(registerAck.dstMac)", for: .debug)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let session = self.makeSession(dstMac: registerAck.srcMac, remoteAddress: remoteAddress) else {
|
||||||
|
SDLLogger.log("[SDLContext] didReadRegisterAck get unsupported remoteAddress: \(remoteAddress)", for: .debug)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.addSession(session)]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func makeSession(dstMac: Data, remoteAddress: SocketAddress) -> Session? {
|
||||||
|
guard let addressType = Self.addressType(from: remoteAddress) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return Session(dstMac: dstMac, natAddress: remoteAddress, addressType: addressType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func addressType(from remoteAddress: SocketAddress) -> Session.AddressType? {
|
||||||
|
switch remoteAddress {
|
||||||
|
case .v4:
|
||||||
|
return .v4
|
||||||
|
case .v6:
|
||||||
|
return .v6
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user