fix SuperClient
This commit is contained in:
parent
ae40d46d6f
commit
a648fb2204
@ -6,10 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import NIOCore
|
|
||||||
import Network
|
import Network
|
||||||
import CryptoKit
|
|
||||||
import Security
|
|
||||||
|
|
||||||
// 定义错误类型,便于上层处理
|
// 定义错误类型,便于上层处理
|
||||||
enum SDLSuperError: Error {
|
enum SDLSuperError: Error {
|
||||||
@ -34,7 +31,7 @@ actor SDLSuperClient {
|
|||||||
|
|
||||||
private var state: State = .idle
|
private var state: State = .idle
|
||||||
|
|
||||||
private let frameParser: SDLQUICFrameParser
|
private let frameParser: SDLSuperFrameParser
|
||||||
|
|
||||||
// 数据流
|
// 数据流
|
||||||
public var messageStream: AsyncThrowingStream<SDLQUICInboundMessage, Error>
|
public var messageStream: AsyncThrowingStream<SDLQUICInboundMessage, Error>
|
||||||
@ -52,7 +49,7 @@ actor SDLSuperClient {
|
|||||||
self.serverEndpoint = serverEndpoint
|
self.serverEndpoint = serverEndpoint
|
||||||
self.port = port
|
self.port = port
|
||||||
|
|
||||||
self.frameParser = SDLQUICFrameParser(maxBufferSize: maxBufferSize)
|
self.frameParser = SDLSuperFrameParser(maxBufferSize: maxBufferSize)
|
||||||
(self.messageStream, self.messageCont) = AsyncThrowingStream.makeStream(of: SDLQUICInboundMessage.self)
|
(self.messageStream, self.messageCont) = AsyncThrowingStream.makeStream(of: SDLQUICInboundMessage.self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +71,7 @@ actor SDLSuperClient {
|
|||||||
options.securityProtocolOptions,
|
options.securityProtocolOptions,
|
||||||
{ _, trust, complete in
|
{ _, trust, complete in
|
||||||
// 执行公钥校验
|
// 执行公钥校验
|
||||||
complete(TLSVerifier.verify(trust: trust, host: serverEndpoint.host))
|
complete(SDLSuperTLSVerifier.verify(trust: trust, host: serverEndpoint.host))
|
||||||
},
|
},
|
||||||
queue
|
queue
|
||||||
)
|
)
|
||||||
@ -146,7 +143,7 @@ actor SDLSuperClient {
|
|||||||
let frames = try self.frameParser.parseFrames(data: data)
|
let frames = try self.frameParser.parseFrames(data: data)
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
if let message = SDLQUICCodec.decode(frame: frame) {
|
if let message = SDLSuperCodec.decode(frame: frame) {
|
||||||
self.messageCont.yield(message)
|
self.messageCont.yield(message)
|
||||||
} else {
|
} else {
|
||||||
self.finishMessageContinuationIfNeed(throwing: .decodeError("invalid message"))
|
self.finishMessageContinuationIfNeed(throwing: .decodeError("invalid message"))
|
||||||
@ -232,183 +229,3 @@ actor SDLSuperClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --MARK: 数据累加器
|
|
||||||
extension SDLSuperClient {
|
|
||||||
|
|
||||||
class SDLQUICFrameParser {
|
|
||||||
private let allocator = ByteBufferAllocator()
|
|
||||||
// 最大缓冲区区为2M
|
|
||||||
private let maxPacketSize: Int = 64 * 1024
|
|
||||||
private let maxBufferSize: Int
|
|
||||||
private var buffer: ByteBuffer
|
|
||||||
|
|
||||||
init(maxBufferSize: Int) {
|
|
||||||
self.buffer = allocator.buffer(capacity: maxBufferSize)
|
|
||||||
self.maxBufferSize = maxBufferSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试解析数据
|
|
||||||
public func parseFrames(data: Data) throws -> [ByteBuffer] {
|
|
||||||
self.buffer.writeBytes(data)
|
|
||||||
|
|
||||||
guard buffer.readableBytes >= 2 else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
var frames: [ByteBuffer] = []
|
|
||||||
while true {
|
|
||||||
guard let len = buffer.getInteger(at: buffer.readerIndex, endianness: .big, as: UInt16.self) else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len > self.maxPacketSize {
|
|
||||||
throw SDLSuperError.packetTooLarge
|
|
||||||
}
|
|
||||||
|
|
||||||
guard buffer.readableBytes >= len + 2 else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.moveReaderIndex(forwardBy: 2)
|
|
||||||
if let buf = buffer.readSlice(length: Int(len)) {
|
|
||||||
frames.append(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let threshold = maxBufferSize / 10 * 6
|
|
||||||
if buffer.readerIndex > threshold {
|
|
||||||
buffer.discardReadBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
return frames
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --MARK: 编解码器
|
|
||||||
extension SDLSuperClient {
|
|
||||||
|
|
||||||
enum SDLQUICCodec {
|
|
||||||
public static func decode(frame: ByteBuffer) -> SDLQUICInboundMessage? {
|
|
||||||
var buffer = frame
|
|
||||||
guard let type = buffer.readInteger(as: UInt8.self),
|
|
||||||
let packetType = SDLPacketType(rawValue: type) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch packetType {
|
|
||||||
case .welcome:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let welcome = try? SDLWelcome(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .welcome(welcome)
|
|
||||||
|
|
||||||
case .registerSuperAck:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let registerSuperAck = try? SDLRegisterSuperAck(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .registerSuperAck(registerSuperAck)
|
|
||||||
case .registerSuperNak:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let registerSuperNak = try? SDLRegisterSuperNak(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .registerSuperNak(registerSuperNak)
|
|
||||||
case .peerInfo:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let peerInfo = try? SDLPeerInfo(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .peerInfo(peerInfo)
|
|
||||||
case .policyResponse:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let policyResponse = try? SDLPolicyResponse(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .policyReponse(policyResponse)
|
|
||||||
case .arpResponse:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let arpResponse = try? SDLArpResponse(serializedBytes: bytes) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .arpResponse(arpResponse)
|
|
||||||
case .event:
|
|
||||||
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
|
||||||
let event = try? SDLEvent(serializedBytes: bytes) else {
|
|
||||||
SDLLogger.log("SDLSuperClient decode Event Error", for: .debug)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return .event(event)
|
|
||||||
case .pong:
|
|
||||||
return .pong
|
|
||||||
default:
|
|
||||||
SDLLogger.log("SDLSuperClient decode miss type: \(type)", for: .debug)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --MARK: tls验证
|
|
||||||
extension SDLSuperClient {
|
|
||||||
|
|
||||||
enum TLSVerifier {
|
|
||||||
// 你的 Base64 公钥指纹
|
|
||||||
static let pinnedPublicKeyHashes = [
|
|
||||||
"Q41r6hbMWEVyxo6heNAH4Wx/TH5NNOWlNif9bewcJ3E="
|
|
||||||
]
|
|
||||||
|
|
||||||
static func verify(trust: sec_trust_t, host: String) -> Bool {
|
|
||||||
let secTrust = sec_trust_copy_ref(trust).takeRetainedValue()
|
|
||||||
|
|
||||||
// --- Step 1: 系统验证 ---
|
|
||||||
var error: CFError?
|
|
||||||
guard SecTrustEvaluateWithError(secTrust, &error) else {
|
|
||||||
SDLLogger.log("❌ 系统证书验证失败: \(error?.localizedDescription ?? "未知错误")", for: .debug)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Step 2: 主机名验证 ---
|
|
||||||
let policy = SecPolicyCreateSSL(true, host as CFString)
|
|
||||||
SecTrustSetPolicies(secTrust, policy)
|
|
||||||
|
|
||||||
guard SecTrustEvaluateWithError(secTrust, &error) else {
|
|
||||||
SDLLogger.log("❌ 主机名校验失败: \(error?.localizedDescription ?? "未知错误")", for: .debug)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Step 3: 获取叶子证书 ---
|
|
||||||
guard let chain = SecTrustCopyCertificateChain(secTrust) as? [SecCertificate],
|
|
||||||
let leafCertificate = chain.first else {
|
|
||||||
SDLLogger.log("❌ 无法获取证书链或叶子证书", for: .debug)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Step 4: 提取公钥 ---
|
|
||||||
guard let publicKey = SecCertificateCopyKey(leafCertificate),
|
|
||||||
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? else {
|
|
||||||
SDLLogger.log("❌ 无法提取公钥", for: .debug)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Step 5: SHA256 校验 ---
|
|
||||||
let hash = SHA256.hash(data: publicKeyData)
|
|
||||||
let hashBase64 = Data(hash).base64EncodedString()
|
|
||||||
|
|
||||||
if pinnedPublicKeyHashes.contains(hashBase64) {
|
|
||||||
SDLLogger.log("✅ 公钥校验通过", for: .debug)
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
SDLLogger.log("⚠️ 公钥不匹配! 收到: \(hashBase64)", for: .debug)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
71
Tun/Super/SDLSuperCodec.swift
Normal file
71
Tun/Super/SDLSuperCodec.swift
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// SDLSuperCodec.swift
|
||||||
|
// punchnet
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2026/5/22.
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
enum SDLSuperCodec {
|
||||||
|
public static func decode(frame: ByteBuffer) -> SDLQUICInboundMessage? {
|
||||||
|
var buffer = frame
|
||||||
|
guard let type = buffer.readInteger(as: UInt8.self),
|
||||||
|
let packetType = SDLPacketType(rawValue: type) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch packetType {
|
||||||
|
case .welcome:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let welcome = try? SDLWelcome(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .welcome(welcome)
|
||||||
|
|
||||||
|
case .registerSuperAck:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let registerSuperAck = try? SDLRegisterSuperAck(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .registerSuperAck(registerSuperAck)
|
||||||
|
case .registerSuperNak:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let registerSuperNak = try? SDLRegisterSuperNak(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .registerSuperNak(registerSuperNak)
|
||||||
|
case .peerInfo:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let peerInfo = try? SDLPeerInfo(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .peerInfo(peerInfo)
|
||||||
|
case .policyResponse:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let policyResponse = try? SDLPolicyResponse(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .policyReponse(policyResponse)
|
||||||
|
case .arpResponse:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let arpResponse = try? SDLArpResponse(serializedBytes: bytes) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .arpResponse(arpResponse)
|
||||||
|
case .event:
|
||||||
|
guard let bytes = buffer.readBytes(length: buffer.readableBytes),
|
||||||
|
let event = try? SDLEvent(serializedBytes: bytes) else {
|
||||||
|
SDLLogger.log("SDLSuperClient decode Event Error", for: .debug)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return .event(event)
|
||||||
|
case .pong:
|
||||||
|
return .pong
|
||||||
|
default:
|
||||||
|
SDLLogger.log("SDLSuperClient decode miss type: \(type)", for: .debug)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Tun/Super/SDLSuperFrameParser.swift
Normal file
58
Tun/Super/SDLSuperFrameParser.swift
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// SDLSuperFrameParser.swift
|
||||||
|
// punchnet
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2026/5/22.
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
final class SDLSuperFrameParser {
|
||||||
|
private let allocator = ByteBufferAllocator()
|
||||||
|
// 最大缓冲区区为2M
|
||||||
|
private let maxPacketSize: Int = 64 * 1024
|
||||||
|
private let maxBufferSize: Int
|
||||||
|
private var buffer: ByteBuffer
|
||||||
|
|
||||||
|
init(maxBufferSize: Int) {
|
||||||
|
self.buffer = allocator.buffer(capacity: maxBufferSize)
|
||||||
|
self.maxBufferSize = maxBufferSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试解析数据
|
||||||
|
public func parseFrames(data: Data) throws -> [ByteBuffer] {
|
||||||
|
self.buffer.writeBytes(data)
|
||||||
|
|
||||||
|
guard buffer.readableBytes >= 2 else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
var frames: [ByteBuffer] = []
|
||||||
|
while true {
|
||||||
|
guard let len = buffer.getInteger(at: buffer.readerIndex, endianness: .big, as: UInt16.self) else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len > self.maxPacketSize {
|
||||||
|
throw SDLSuperError.packetTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
guard buffer.readableBytes >= len + 2 else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.moveReaderIndex(forwardBy: 2)
|
||||||
|
if let buf = buffer.readSlice(length: Int(len)) {
|
||||||
|
frames.append(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let threshold = maxBufferSize / 10 * 6
|
||||||
|
if buffer.readerIndex > threshold {
|
||||||
|
buffer.discardReadBytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
Tun/Super/SDLSuperTLSVerifier.swift
Normal file
63
Tun/Super/SDLSuperTLSVerifier.swift
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//
|
||||||
|
// SDLSuperTLSVerifier.swift
|
||||||
|
// punchnet
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2026/5/22.
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
import CryptoKit
|
||||||
|
import Security
|
||||||
|
|
||||||
|
enum SDLSuperTLSVerifier {
|
||||||
|
// 你的 Base64 公钥指纹
|
||||||
|
static let pinnedPublicKeyHashes = [
|
||||||
|
"Q41r6hbMWEVyxo6heNAH4Wx/TH5NNOWlNif9bewcJ3E="
|
||||||
|
]
|
||||||
|
|
||||||
|
static func verify(trust: sec_trust_t, host: String) -> Bool {
|
||||||
|
let secTrust = sec_trust_copy_ref(trust).takeRetainedValue()
|
||||||
|
|
||||||
|
// --- Step 1: 系统验证 ---
|
||||||
|
var error: CFError?
|
||||||
|
guard SecTrustEvaluateWithError(secTrust, &error) else {
|
||||||
|
SDLLogger.log("❌ 系统证书验证失败: \(error?.localizedDescription ?? "未知错误")", for: .debug)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 2: 主机名验证 ---
|
||||||
|
let policy = SecPolicyCreateSSL(true, host as CFString)
|
||||||
|
SecTrustSetPolicies(secTrust, policy)
|
||||||
|
|
||||||
|
guard SecTrustEvaluateWithError(secTrust, &error) else {
|
||||||
|
SDLLogger.log("❌ 主机名校验失败: \(error?.localizedDescription ?? "未知错误")", for: .debug)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 3: 获取叶子证书 ---
|
||||||
|
guard let chain = SecTrustCopyCertificateChain(secTrust) as? [SecCertificate],
|
||||||
|
let leafCertificate = chain.first else {
|
||||||
|
SDLLogger.log("❌ 无法获取证书链或叶子证书", for: .debug)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 4: 提取公钥 ---
|
||||||
|
guard let publicKey = SecCertificateCopyKey(leafCertificate),
|
||||||
|
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? else {
|
||||||
|
SDLLogger.log("❌ 无法提取公钥", for: .debug)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 5: SHA256 校验 ---
|
||||||
|
let hash = SHA256.hash(data: publicKeyData)
|
||||||
|
let hashBase64 = Data(hash).base64EncodedString()
|
||||||
|
|
||||||
|
if pinnedPublicKeyHashes.contains(hashBase64) {
|
||||||
|
SDLLogger.log("✅ 公钥校验通过", for: .debug)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
SDLLogger.log("⚠️ 公钥不匹配! 收到: \(hashBase64)", for: .debug)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user