fix SuperClient

This commit is contained in:
anlicheng 2026-05-22 14:57:13 +08:00
parent ae40d46d6f
commit a648fb2204
4 changed files with 196 additions and 187 deletions

View File

@ -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
}
}
}
}

View 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
}
}
}

View 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
}
}

View 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
}
}
}