解决语法级别的错误
This commit is contained in:
parent
cd4c977b83
commit
6faff2e6cc
@ -37,7 +37,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
let stunServersStr = options["stun_servers"] as! String
|
let stunServersStr = options["stun_servers"] as! String
|
||||||
let noticePort = options["notice_port"] as! Int
|
let noticePort = options["notice_port"] as! Int
|
||||||
let token = options["token"] as! String
|
let token = options["token"] as! String
|
||||||
let networkCode = options["network_code"] as! String
|
let accessToken = options["access_token"] as! String
|
||||||
let clientId = options["client_id"] as! String
|
let clientId = options["client_id"] as! String
|
||||||
let remoteDnsServer = options["remote_dns_server"] as! String
|
let remoteDnsServer = options["remote_dns_server"] as! String
|
||||||
let hostname = options["hostname"] as! String
|
let hostname = options["hostname"] as! String
|
||||||
@ -61,7 +61,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog("[PacketTunnelProvider] client_id: \(clientId), token: \(token), network_code: \(networkCode)")
|
NSLog("[PacketTunnelProvider] client_id: \(clientId), token: \(token)")
|
||||||
|
|
||||||
let config = SDLConfiguration(version: 1,
|
let config = SDLConfiguration(version: 1,
|
||||||
installedChannel: installed_channel,
|
installedChannel: installed_channel,
|
||||||
@ -71,7 +71,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
noticePort: noticePort,
|
noticePort: noticePort,
|
||||||
token: token,
|
token: token,
|
||||||
networkCode: networkCode,
|
accessToken: accessToken,
|
||||||
remoteDnsServer: remoteDnsServer,
|
remoteDnsServer: remoteDnsServer,
|
||||||
hostname: hostname)
|
hostname: hostname)
|
||||||
// 加密算法
|
// 加密算法
|
||||||
|
|||||||
179
Tun/Punchnet/Actors/SDLNATProberActor.swift
Normal file
179
Tun/Punchnet/Actors/SDLNATProberActor.swift
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
//
|
||||||
|
// SDLNATProberActor.swift
|
||||||
|
// punchnet
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2026/1/28.
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
actor SDLNATProberActor {
|
||||||
|
|
||||||
|
// MARK: - NAT Type
|
||||||
|
|
||||||
|
enum NatType: UInt8, Encodable {
|
||||||
|
case blocked = 0
|
||||||
|
case noNat = 1
|
||||||
|
case fullCone = 2
|
||||||
|
case portRestricted = 3
|
||||||
|
case coneRestricted = 4
|
||||||
|
case symmetric = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Internal State
|
||||||
|
|
||||||
|
private enum State {
|
||||||
|
case idle
|
||||||
|
case waiting(step: Step)
|
||||||
|
case finished
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Step: Int {
|
||||||
|
case step1 = 1
|
||||||
|
case step2 = 2
|
||||||
|
case step3 = 3
|
||||||
|
case step4 = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: State = .idle
|
||||||
|
|
||||||
|
// MARK: - Dependencies
|
||||||
|
|
||||||
|
private let udpHole: SDLUDPHoleActor
|
||||||
|
private let config: SDLConfiguration
|
||||||
|
private let logger: SDLLogger
|
||||||
|
|
||||||
|
// MARK: - Probe Data
|
||||||
|
|
||||||
|
private var natAddress1: SocketAddress?
|
||||||
|
private var natAddress2: SocketAddress?
|
||||||
|
|
||||||
|
// MARK: - Completion
|
||||||
|
|
||||||
|
private var onFinished: ((NatType) -> Void)?
|
||||||
|
|
||||||
|
private var cookieId: UInt32 = 1
|
||||||
|
|
||||||
|
// MARK: - Init
|
||||||
|
|
||||||
|
init(udpHole: SDLUDPHoleActor, config: SDLConfiguration, logger: SDLLogger) {
|
||||||
|
self.udpHole = udpHole
|
||||||
|
self.config = config
|
||||||
|
self.logger = logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public API
|
||||||
|
|
||||||
|
/// 启动 NAT 探测(一次性)
|
||||||
|
func start(onFinished: @escaping (NatType) -> Void) async {
|
||||||
|
guard case .idle = state else {
|
||||||
|
logger.log("[NAT] probe already started", level: .warning)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.onFinished = onFinished
|
||||||
|
transition(to: .waiting(step: .step1))
|
||||||
|
await self.sendProbe(step: .step1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// UDP 层收到 STUN 响应后调用
|
||||||
|
func handleProbeReply(from address: SocketAddress, reply: SDLStunProbeReply) async {
|
||||||
|
guard case .waiting(let currentStep) = state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch currentStep {
|
||||||
|
case .step1:
|
||||||
|
let localAddress = await self.udpHole.getLocalAddress()
|
||||||
|
if address == localAddress {
|
||||||
|
finish(.noNat)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
natAddress1 = address
|
||||||
|
transition(to: .waiting(step: .step2))
|
||||||
|
await self.sendProbe(step: .step2)
|
||||||
|
|
||||||
|
case .step2:
|
||||||
|
natAddress2 = address
|
||||||
|
// 如果natAddress2 的IP地址与上次回来的IP是不一样的,它就是对称型NAT; 这次的包也一定能发成功并收到
|
||||||
|
// 如果ip地址变了,这说明{dstIp, dstPort, srcIp, srcPort}, 其中有一个变了;则用新的ip地址
|
||||||
|
if let ip1 = natAddress1?.ipAddress, let ip2 = natAddress2?.ipAddress, ip1 != ip2 {
|
||||||
|
finish(.symmetric)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
transition(to: .waiting(step: .step3))
|
||||||
|
await self.sendProbe(step: .step3)
|
||||||
|
case .step3:
|
||||||
|
// step3: ip1:port1 <---- ip2:port2 (ip地址和port都变的情况)
|
||||||
|
// 如果能收到的,说明是完全锥形 说明是IP地址限制锥型NAT,如果不能收到说明是端口限制锥型。
|
||||||
|
finish(.fullCone)
|
||||||
|
case .step4:
|
||||||
|
finish(.coneRestricted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 超时事件(由外部 Timer / Task 驱动)
|
||||||
|
func handleTimeout() async {
|
||||||
|
guard case .waiting(let currentStep) = state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch currentStep {
|
||||||
|
case .step3:
|
||||||
|
transition(to: .waiting(step: .step4))
|
||||||
|
await sendProbe(step: .step4)
|
||||||
|
case .step4:
|
||||||
|
finish(.portRestricted)
|
||||||
|
default:
|
||||||
|
finish(.blocked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Internal helpers
|
||||||
|
|
||||||
|
private func sendProbe(step: Step) async {
|
||||||
|
let addressArray = config.stunProbeSocketAddressArray
|
||||||
|
|
||||||
|
let remote: SocketAddress
|
||||||
|
let attr: SDLProbeAttr
|
||||||
|
|
||||||
|
switch step {
|
||||||
|
case .step1:
|
||||||
|
remote = addressArray[0][0]
|
||||||
|
attr = .none
|
||||||
|
case .step2:
|
||||||
|
remote = addressArray[1][1]
|
||||||
|
attr = .none
|
||||||
|
case .step3:
|
||||||
|
remote = addressArray[0][0]
|
||||||
|
attr = .peer
|
||||||
|
case .step4:
|
||||||
|
remote = addressArray[0][0]
|
||||||
|
attr = .port
|
||||||
|
}
|
||||||
|
|
||||||
|
var stunProbe = SDLStunProbe()
|
||||||
|
stunProbe.cookie = self.cookieId
|
||||||
|
stunProbe.attr = UInt32(attr.rawValue)
|
||||||
|
|
||||||
|
self.cookieId &+= 1
|
||||||
|
|
||||||
|
await self.udpHole.send(type: .stunProbe, data: try! stunProbe.serializedData(), remoteAddress: remote)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func finish(_ type: NatType) {
|
||||||
|
guard case .finished = state else {
|
||||||
|
transition(to: .finished)
|
||||||
|
logger.log("[NAT] finished with \(type)", level: .info)
|
||||||
|
onFinished?(type)
|
||||||
|
onFinished = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func transition(to newState: State) {
|
||||||
|
state = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,32 +12,32 @@ import SwiftProtobuf
|
|||||||
|
|
||||||
// 处理和sn-server服务器之间的通讯
|
// 处理和sn-server服务器之间的通讯
|
||||||
actor SDLUDPHoleActor {
|
actor SDLUDPHoleActor {
|
||||||
typealias HoleMessage = (SocketAddress, SDLHoleInboundMessage)
|
|
||||||
|
|
||||||
private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||||
private let asyncChannel: NIOAsyncChannel<AddressedEnvelope<ByteBuffer>, AddressedEnvelope<ByteBuffer>>
|
private let asyncChannel: NIOAsyncChannel<AddressedEnvelope<ByteBuffer>, AddressedEnvelope<ByteBuffer>>
|
||||||
private let (writeStream, writeContinuation) = AsyncStream.makeStream(of: UDPMessage.self, bufferingPolicy: .unbounded)
|
private let (writeStream, writeContinuation) = AsyncStream.makeStream(of: UDPHoleOutboundMessage.self, bufferingPolicy: .unbounded)
|
||||||
|
|
||||||
private var cookieGenerator = SDLIdGenerator(seed: 1)
|
|
||||||
private var promises: [UInt32:EventLoopPromise<SDLStunProbeReply>] = [:]
|
|
||||||
public var localAddress: SocketAddress?
|
public var localAddress: SocketAddress?
|
||||||
|
public let eventStream: AsyncStream<UDPHoleEvent>
|
||||||
public let messageStream: AsyncStream<HoleMessage>
|
private let eventContinuation: AsyncStream<UDPHoleEvent>.Continuation
|
||||||
private let messageContinuation: AsyncStream<HoleMessage>.Continuation
|
|
||||||
|
|
||||||
private let logger: SDLLogger
|
private let logger: SDLLogger
|
||||||
|
|
||||||
struct UDPMessage {
|
struct UDPHoleOutboundMessage {
|
||||||
let remoteAddress: SocketAddress
|
let remoteAddress: SocketAddress
|
||||||
let type: SDLPacketType
|
let type: SDLPacketType
|
||||||
let data: Data
|
let data: Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum UDPHoleEvent {
|
||||||
|
case ready
|
||||||
|
case message(SocketAddress, SDLHoleInboundMessage)
|
||||||
|
}
|
||||||
|
|
||||||
// 启动函数
|
// 启动函数
|
||||||
init(logger: SDLLogger) async throws {
|
init(logger: SDLLogger) async throws {
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
(self.messageStream, self.messageContinuation) = AsyncStream.makeStream(of: HoleMessage.self, bufferingPolicy: .unbounded)
|
(self.eventStream, self.eventContinuation) = AsyncStream.makeStream(of: UDPHoleEvent.self, bufferingPolicy: .unbounded)
|
||||||
|
|
||||||
let bootstrap = DatagramBootstrap(group: group)
|
let bootstrap = DatagramBootstrap(group: group)
|
||||||
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
|
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
|
||||||
@ -56,8 +56,9 @@ actor SDLUDPHoleActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func start() async throws {
|
func start() async throws {
|
||||||
try await withTaskCancellationHandler {
|
|
||||||
try await self.asyncChannel.executeThenClose {inbound, outbound in
|
try await self.asyncChannel.executeThenClose {inbound, outbound in
|
||||||
|
self.eventContinuation.yield(.ready)
|
||||||
|
|
||||||
try await withThrowingTaskGroup(of: Void.self) { group in
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
||||||
group.addTask {
|
group.addTask {
|
||||||
defer {
|
defer {
|
||||||
@ -71,16 +72,7 @@ actor SDLUDPHoleActor {
|
|||||||
let remoteAddress = envelope.remoteAddress
|
let remoteAddress = envelope.remoteAddress
|
||||||
do {
|
do {
|
||||||
if let message = try Self.decode(buffer: &buffer) {
|
if let message = try Self.decode(buffer: &buffer) {
|
||||||
switch message {
|
self.eventContinuation.yield(.message(remoteAddress, message))
|
||||||
case .data(let data):
|
|
||||||
self.logger.log("[SDLUDPHole] read data: \(data.format()), from: \(remoteAddress)", level: .debug)
|
|
||||||
self.messageContinuation.yield((remoteAddress, .data(data)))
|
|
||||||
case .stunProbeReply(let probeReply):
|
|
||||||
// 执行并移除回调
|
|
||||||
await self.trigger(probeReply: probeReply)
|
|
||||||
default:
|
|
||||||
()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.logger.log("[SDLUDPHole] decode message, get null", level: .warning)
|
self.logger.log("[SDLUDPHole] decode message, get null", level: .warning)
|
||||||
}
|
}
|
||||||
@ -113,51 +105,16 @@ actor SDLUDPHoleActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} onCancel: {
|
|
||||||
self.writeContinuation.finish()
|
|
||||||
self.messageContinuation.finish()
|
|
||||||
self.logger.log("[SDLUDPHole] withTaskCancellationHandler cancel")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCookieId() -> UInt32 {
|
func getLocalAddress() -> SocketAddress? {
|
||||||
return self.cookieGenerator.nextId()
|
return self.localAddress
|
||||||
}
|
|
||||||
|
|
||||||
// 探测tun信息
|
|
||||||
func stunProbe(remoteAddress: SocketAddress, attr: SDLProbeAttr = .none, timeout: Int = 5) async throws -> SDLStunProbeReply {
|
|
||||||
return try await self._stunProbe(remoteAddress: remoteAddress, attr: attr, timeout: timeout).get()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func _stunProbe(remoteAddress: SocketAddress, attr: SDLProbeAttr = .none, timeout: Int) -> EventLoopFuture<SDLStunProbeReply> {
|
|
||||||
let cookie = self.cookieGenerator.nextId()
|
|
||||||
var stunProbe = SDLStunProbe()
|
|
||||||
stunProbe.cookie = cookie
|
|
||||||
stunProbe.attr = UInt32(attr.rawValue)
|
|
||||||
self.send( type: .stunProbe, data: try! stunProbe.serializedData(), remoteAddress: remoteAddress)
|
|
||||||
self.logger.log("[SDLUDPHole] stunProbe: \(remoteAddress)", level: .debug)
|
|
||||||
|
|
||||||
let promise = self.asyncChannel.channel.eventLoop.makePromise(of: SDLStunProbeReply.self)
|
|
||||||
self.promises[cookie] = promise
|
|
||||||
|
|
||||||
return promise.futureResult
|
|
||||||
}
|
|
||||||
|
|
||||||
private func trigger(probeReply: SDLStunProbeReply) {
|
|
||||||
let id = probeReply.cookie
|
|
||||||
// 执行并移除回调
|
|
||||||
if let promise = self.promises[id] {
|
|
||||||
self.asyncChannel.channel.eventLoop.execute {
|
|
||||||
promise.succeed(probeReply)
|
|
||||||
}
|
|
||||||
self.promises.removeValue(forKey: id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: client-client apis
|
// MARK: client-client apis
|
||||||
// 处理写入逻辑
|
// 处理写入逻辑
|
||||||
func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) {
|
func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) {
|
||||||
let message = UDPMessage(remoteAddress: remoteAddress, type: type, data: data)
|
let message = UDPHoleOutboundMessage(remoteAddress: remoteAddress, type: type, data: data)
|
||||||
self.writeContinuation.yield(message)
|
self.writeContinuation.yield(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +195,7 @@ actor SDLUDPHoleActor {
|
|||||||
deinit {
|
deinit {
|
||||||
try? self.group.syncShutdownGracefully()
|
try? self.group.syncShutdownGracefully()
|
||||||
self.writeContinuation.finish()
|
self.writeContinuation.finish()
|
||||||
self.messageContinuation.finish()
|
self.eventContinuation.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,9 +63,9 @@ public class SDLConfiguration {
|
|||||||
|
|
||||||
let clientId: String
|
let clientId: String
|
||||||
let token: String
|
let token: String
|
||||||
let networkCode: String
|
let accessToken: String
|
||||||
|
|
||||||
public init(version: UInt8, installedChannel: String, superHost: String, superPort: Int, stunServers: [StunServer], clientId: String, noticePort: Int, token: String, networkCode: String, remoteDnsServer: String, hostname: String) {
|
public init(version: UInt8, installedChannel: String, superHost: String, superPort: Int, stunServers: [StunServer], clientId: String, noticePort: Int, token: String, accessToken: String, remoteDnsServer: String, hostname: String) {
|
||||||
self.version = version
|
self.version = version
|
||||||
self.installedChannel = installedChannel
|
self.installedChannel = installedChannel
|
||||||
self.superHost = superHost
|
self.superHost = superHost
|
||||||
@ -74,7 +74,7 @@ public class SDLConfiguration {
|
|||||||
self.clientId = clientId
|
self.clientId = clientId
|
||||||
self.noticePort = noticePort
|
self.noticePort = noticePort
|
||||||
self.token = token
|
self.token = token
|
||||||
self.networkCode = networkCode
|
self.accessToken = accessToken
|
||||||
self.remoteDnsServer = remoteDnsServer
|
self.remoteDnsServer = remoteDnsServer
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,10 +30,8 @@ public class SDLContext {
|
|||||||
|
|
||||||
let config: SDLConfiguration
|
let config: SDLConfiguration
|
||||||
|
|
||||||
// nat映射的相关信息, 暂时没有用处
|
|
||||||
//var natAddress: SDLNatAddress?
|
|
||||||
// nat的网络类型
|
// nat的网络类型
|
||||||
var natType: NatType = .blocked
|
var natType: SDLNATProberActor.NatType = .blocked
|
||||||
|
|
||||||
// AES加密,授权通过后,对象才会被创建
|
// AES加密,授权通过后,对象才会被创建
|
||||||
var aesCipher: AESCipher
|
var aesCipher: AESCipher
|
||||||
@ -51,6 +49,9 @@ public class SDLContext {
|
|||||||
// dns的client对象
|
// dns的client对象
|
||||||
var dnsClientActor: SDLDNSClientActor?
|
var dnsClientActor: SDLDNSClientActor?
|
||||||
|
|
||||||
|
// 网络探测对象
|
||||||
|
var proberActor: SDLNATProberActor?
|
||||||
|
|
||||||
// 数据包读取任务
|
// 数据包读取任务
|
||||||
private var readTask: Task<(), Never>?
|
private var readTask: Task<(), Never>?
|
||||||
|
|
||||||
@ -162,7 +163,6 @@ public class SDLContext {
|
|||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|
||||||
if let udpHoleActor = self.udpHoleActor {
|
if let udpHoleActor = self.udpHoleActor {
|
||||||
let cookie = await udpHoleActor.getCookieId()
|
|
||||||
var stunRequest = SDLStunRequest()
|
var stunRequest = SDLStunRequest()
|
||||||
stunRequest.clientID = self.config.clientId
|
stunRequest.clientID = self.config.clientId
|
||||||
stunRequest.networkID = self.config.networkAddress.networkId
|
stunRequest.networkID = self.config.networkAddress.networkId
|
||||||
@ -172,22 +172,26 @@ public class SDLContext {
|
|||||||
|
|
||||||
let remoteAddress = self.config.stunSocketAddress
|
let remoteAddress = self.config.stunSocketAddress
|
||||||
await udpHoleActor.send(type: .stunRequest, data: try stunRequest.serializedData(), remoteAddress: remoteAddress)
|
await udpHoleActor.send(type: .stunRequest, data: try stunRequest.serializedData(), remoteAddress: remoteAddress)
|
||||||
self.lastCookie = cookie
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group.addTask {
|
group.addTask {
|
||||||
if let messageStream = self.udpHoleActor?.messageStream {
|
if let eventStream = self.udpHoleActor?.eventStream {
|
||||||
for try await (remoteAddress, message) in messageStream {
|
for try await event in eventStream {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|
||||||
|
switch event {
|
||||||
|
case .ready:
|
||||||
|
try await self.handleUDPHoleReady()
|
||||||
|
case .message(let remoteAddress, let message):
|
||||||
switch message {
|
switch message {
|
||||||
case .registerSuperAck(let registerSuperAck):
|
case .registerSuperAck(let registerSuperAck):
|
||||||
await self.handleRegisterSuperAck(registerSuperAck: registerSuperAck)
|
await self.handleRegisterSuperAck(registerSuperAck: registerSuperAck)
|
||||||
case .registerSuperNak(let registerSuperNak):
|
case .registerSuperNak(let registerSuperNak):
|
||||||
await self.handleRegisterSuperNak(nakPacket: registerSuperNak)
|
await self.handleRegisterSuperNak(nakPacket: registerSuperNak)
|
||||||
case .peerInfo(let peerInfo):
|
case .peerInfo(let peerInfo):
|
||||||
()
|
await self.puncherActor.handlePeerInfo(peerInfo: peerInfo)
|
||||||
case .event(let event):
|
case .event(let event):
|
||||||
try await self.handleEvent(event: event)
|
try await self.handleEvent(event: event)
|
||||||
case .stunReply(let stunReply):
|
case .stunReply(let stunReply):
|
||||||
@ -200,8 +204,7 @@ public class SDLContext {
|
|||||||
try await self.handleRegister(remoteAddress: remoteAddress, register: register)
|
try await self.handleRegister(remoteAddress: remoteAddress, register: register)
|
||||||
case .registerAck(let registerAck):
|
case .registerAck(let registerAck):
|
||||||
await self.handleRegisterAck(remoteAddress: remoteAddress, registerAck: registerAck)
|
await self.handleRegisterAck(remoteAddress: remoteAddress, registerAck: registerAck)
|
||||||
default:
|
}
|
||||||
self.logger.log("get unknown message: \(message)", level: .error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +223,8 @@ public class SDLContext {
|
|||||||
switch event {
|
switch event {
|
||||||
case .changed:
|
case .changed:
|
||||||
// 需要重新探测网络的nat类型
|
// 需要重新探测网络的nat类型
|
||||||
self.natType = await self.getNatType()
|
//self.natType = await self.getNatType()
|
||||||
|
|
||||||
self.logger.log("didNetworkPathChanged, nat type is: \(self.natType)", level: .info)
|
self.logger.log("didNetworkPathChanged, nat type is: \(self.natType)", level: .info)
|
||||||
case .unreachable:
|
case .unreachable:
|
||||||
self.logger.log("didNetworkPathUnreachable", level: .warning)
|
self.logger.log("didNetworkPathUnreachable", level: .warning)
|
||||||
@ -258,24 +262,30 @@ public class SDLContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private func handleMessage(remoteAddress: SocketAddress, message: SDLHoleInboundMessage) async throws {
|
private func handleUDPHoleReady() async throws {
|
||||||
// switch message {
|
await self.puncherActor.setUDPHoleActor(udpHoleActor: self.udpHoleActor)
|
||||||
//// case .ready:
|
|
||||||
//// await self.puncherActor.setSuperClientActor(superClientActor: self.superClientActor)
|
// 开始探测nat的类型
|
||||||
////
|
if let udpHoleActor = self.udpHoleActor {
|
||||||
//// self.logger.log("[SDLContext] get registerSuper, mac address: \(SDLUtil.formatMacAddress(mac: self.devAddr.mac))", level: .debug)
|
self.proberActor = SDLNATProberActor(udpHole: udpHoleActor, config: self.config, logger: self.logger)
|
||||||
//// var registerSuper = SDLRegisterSuper()
|
await self.proberActor?.start { natType in
|
||||||
//// registerSuper.version = UInt32(self.config.version)
|
self.natType = natType
|
||||||
//// registerSuper.clientID = self.config.clientId
|
}
|
||||||
//// registerSuper.devAddr = self.devAddr
|
}
|
||||||
//// registerSuper.pubKey = self.rsaCipher.pubKey
|
|
||||||
//// registerSuper.token = self.config.token
|
var registerSuper = SDLRegisterSuper()
|
||||||
//// registerSuper.networkCode = self.config.networkCode
|
registerSuper.pktID = 0
|
||||||
//// registerSuper.hostname = self.config.hostname
|
registerSuper.clientID = self.config.clientId
|
||||||
//// guard let message = try await self.superClientActor?.request(type: .registerSuper, data: try registerSuper.serializedData()) else {
|
registerSuper.networkID = self.config.networkAddress.networkId
|
||||||
//// return
|
registerSuper.mac = self.config.networkAddress.mac
|
||||||
//// }
|
registerSuper.ip = self.config.networkAddress.ip
|
||||||
///
|
registerSuper.maskLen = UInt32(self.config.networkAddress.maskLen)
|
||||||
|
registerSuper.hostname = self.config.hostname
|
||||||
|
registerSuper.pubKey = self.rsaCipher.pubKey
|
||||||
|
registerSuper.accessToken = self.config.accessToken
|
||||||
|
|
||||||
|
await self.udpHoleActor?.send(type: .registerSuper, data: try registerSuper.serializedData(), remoteAddress: self.config.stunSocketAddress)
|
||||||
|
}
|
||||||
|
|
||||||
private func handleRegisterSuperAck(registerSuperAck: SDLRegisterSuperAck) async {
|
private func handleRegisterSuperAck(registerSuperAck: SDLRegisterSuperAck) async {
|
||||||
// 需要对数据通过rsa的私钥解码
|
// 需要对数据通过rsa的私钥解码
|
||||||
@ -549,71 +559,6 @@ public class SDLContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网络类型探测
|
|
||||||
extension SDLContext {
|
|
||||||
// 定义nat类型
|
|
||||||
enum NatType: UInt8, Encodable {
|
|
||||||
case blocked = 0
|
|
||||||
case noNat = 1
|
|
||||||
case fullCone = 2
|
|
||||||
case portRestricted = 3
|
|
||||||
case coneRestricted = 4
|
|
||||||
case symmetric = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前所处的网络的nat类型
|
|
||||||
func getNatType() async -> NatType {
|
|
||||||
guard let udpHole = self.udpHoleActor else {
|
|
||||||
return .blocked
|
|
||||||
}
|
|
||||||
|
|
||||||
let addressArray = config.stunProbeSocketAddressArray
|
|
||||||
// step1: ip1:port1 <---- ip1:port1
|
|
||||||
guard let natAddress1 = await getNatAddress(udpHole, remoteAddress: addressArray[0][0], attr: .none) else {
|
|
||||||
return .blocked
|
|
||||||
}
|
|
||||||
|
|
||||||
// 网络没有在nat下
|
|
||||||
if await natAddress1 == udpHole.localAddress {
|
|
||||||
return .noNat
|
|
||||||
}
|
|
||||||
|
|
||||||
// step2: ip2:port2 <---- ip2:port2
|
|
||||||
guard let natAddress2 = await getNatAddress(udpHole, remoteAddress: addressArray[1][1], attr: .none) else {
|
|
||||||
return .blocked
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果natAddress2 的IP地址与上次回来的IP是不一样的,它就是对称型NAT; 这次的包也一定能发成功并收到
|
|
||||||
// 如果ip地址变了,这说明{dstIp, dstPort, srcIp, srcPort}, 其中有一个变了;则用新的ip地址
|
|
||||||
logger.log("[SDLNatProber] nat_address1: \(natAddress1), nat_address2: \(natAddress2)", level: .debug)
|
|
||||||
if let ipAddress1 = natAddress1.ipAddress, let ipAddress2 = natAddress2.ipAddress, ipAddress1 != ipAddress2 {
|
|
||||||
return .symmetric
|
|
||||||
}
|
|
||||||
|
|
||||||
// step3: ip1:port1 <---- ip2:port2 (ip地址和port都变的情况)
|
|
||||||
// 如果能收到的,说明是完全锥形 说明是IP地址限制锥型NAT,如果不能收到说明是端口限制锥型。
|
|
||||||
if let natAddress3 = await getNatAddress(udpHole, remoteAddress: addressArray[0][0], attr: .peer) {
|
|
||||||
logger.log("[SDLNatProber] nat_address1: \(natAddress1), nat_address2: \(natAddress2), nat_address3: \(natAddress3)", level: .debug)
|
|
||||||
return .fullCone
|
|
||||||
}
|
|
||||||
|
|
||||||
// step3: ip1:port1 <---- ip1:port2 (port改变情况)
|
|
||||||
// 如果能收到的说明是IP地址限制锥型NAT,如果不能收到说明是端口限制锥型。
|
|
||||||
if let natAddress4 = await getNatAddress(udpHole, remoteAddress: addressArray[0][0], attr: .port) {
|
|
||||||
logger.log("[SDLNatProber] nat_address1: \(natAddress1), nat_address2: \(natAddress2), nat_address4: \(natAddress4)", level: .debug)
|
|
||||||
return .coneRestricted
|
|
||||||
} else {
|
|
||||||
return .portRestricted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getNatAddress(_ udpHole: SDLUDPHoleActor, remoteAddress: SocketAddress, attr: SDLProbeAttr) async -> SocketAddress? {
|
|
||||||
let stunProbeReply = try? await udpHole.stunProbe(remoteAddress: remoteAddress, attr: attr, timeout: 5)
|
|
||||||
return stunProbeReply?.socketAddress()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension UInt32 {
|
private extension UInt32 {
|
||||||
// 转换成ip地址
|
// 转换成ip地址
|
||||||
func asIpAddress() -> String {
|
func asIpAddress() -> String {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user