From 4bf1a7160fdb0eb80c54e0f1b6773f8cc6ecaece Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Tue, 26 May 2026 00:47:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0policy=E7=9A=84=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tun/Configuration/SDLConfiguration.swift | 23 +++++++++- Tun/Context/SDLContextActor.swift | 20 +++++++++ Tun/Context/SDLSuperEventProcessor.swift | 6 +++ Tun/Policy/PolicyService.swift | 42 ++++++++++++++++-- Tun/Protobuf/SDLMessage.pb.swift | 56 ++++++++++++++++++++++++ Tun/Protobuf/SDLMessage.swift | 4 ++ Tun/Super/SDLSuperCodec.swift | 6 +++ 7 files changed, 152 insertions(+), 5 deletions(-) diff --git a/Tun/Configuration/SDLConfiguration.swift b/Tun/Configuration/SDLConfiguration.swift index 2df35c7..331ead2 100644 --- a/Tun/Configuration/SDLConfiguration.swift +++ b/Tun/Configuration/SDLConfiguration.swift @@ -73,7 +73,7 @@ public class SDLConfiguration { let hostname: String let accessToken: String let identityId: UInt32 - let acl: ACL + var acl: ACL var exitNode: ExitNode? @@ -220,5 +220,24 @@ extension SDLConfiguration { return UInt16(port) }) } - + +} + +extension SDLConfiguration.ACL { + + init(response: SDLExposedServiceResponse) { + self.init( + tcpPorts: Self.parsePorts(response.tcpPorts), + udpPorts: Self.parsePorts(response.udpPorts) + ) + } + + private static func parsePorts(_ ports: [UInt32]) -> Set { + return Set(ports.compactMap { port in + guard port > 0, port <= UInt32(UInt16.max) else { + return nil + } + return UInt16(port) + }) + } } diff --git a/Tun/Context/SDLContextActor.swift b/Tun/Context/SDLContextActor.swift index 3f9ea3c..ccca43a 100644 --- a/Tun/Context/SDLContextActor.swift +++ b/Tun/Context/SDLContextActor.swift @@ -304,6 +304,8 @@ extension SDLContextActor { case .policyReponse(let policyResponse): // 处理权限的请求问题 await self.policyService.applyPolicyResponse(policyResponse) + case .exposedServiceResponse(let response): + await self.applyExposedServiceResponse(response) case .arpResponse(let arpResponse): SDLLogger.log("[SDLContext] get arp response: \(arpResponse)") await self.arpResolver.handleArpResponse(arpResponse: arpResponse) @@ -416,6 +418,8 @@ extension SDLContextActor { for remoteAddress in remoteAddresses { await self.sendPeerPacket(type: .register, data: registerData, remoteAddress: remoteAddress) } + case .requestExposedService: + await self.requestExposedService() case .shutdown(let message): self.publishTunnelEvent(message: message) @@ -444,6 +448,22 @@ extension SDLContextActor { await self.superServiceProxy.send(type: .registerSuper, data: registerSuperData) } } + + private func requestExposedService() async { + guard let requestData = await self.policyService.makeExposedServiceRequest() else { + return + } + + await self.superServiceProxy.send(type: .exposedServiceRequest, data: requestData) + } + + private func applyExposedServiceResponse(_ response: SDLExposedServiceResponse) async { + guard let acl = await self.policyService.applyExposedServiceResponse(response) else { + return + } + + self.config.acl = acl + } } diff --git a/Tun/Context/SDLSuperEventProcessor.swift b/Tun/Context/SDLSuperEventProcessor.swift index 241f423..5fb0b11 100644 --- a/Tun/Context/SDLSuperEventProcessor.swift +++ b/Tun/Context/SDLSuperEventProcessor.swift @@ -12,6 +12,7 @@ final class SDLSuperEventProcessor { enum ProcessingAction { case removeSession(dstMac: Data) case sendRegister(data: Data, remoteAddresses: [SocketAddress]) + case requestExposedService case shutdown(message: String) case none } @@ -37,6 +38,11 @@ final class SDLSuperEventProcessor { ) case .sendRegister(let sendRegisterEvent): return await self.makeSendRegisterPlan(sendRegisterEvent) + case .exposedServiceChanged: + return .init( + logMessage: "[SDLContext] exposedServiceChanged event", + action: .requestExposedService + ) case .shutdown(let shutdownEvent): return .init(logMessage: nil, action: .shutdown(message: shutdownEvent.message)) case .none: diff --git a/Tun/Policy/PolicyService.swift b/Tun/Policy/PolicyService.swift index a4065c4..3721312 100644 --- a/Tun/Policy/PolicyService.swift +++ b/Tun/Policy/PolicyService.swift @@ -7,28 +7,37 @@ import Foundation +final class ExposedServiceSnapshot: Snapshot { + let acl: SDLConfiguration.ACL + + init(acl: SDLConfiguration.ACL) { + self.acl = acl + } +} + actor PolicyService { // 处理权限控制 private let policyRuleStore: PolicyRuleStore nonisolated private let snapshotPublisher: SnapshotPublisher + nonisolated private let aclPublisher: SnapshotPublisher nonisolated private let flowSessionTable = FlowSessionTable() // 当前节点的identityId值 let identityId: UInt32 - private let acl: SDLConfiguration.ACL + private var latestExposedServiceRequestVersion: UInt32 = 0 init(identityId: UInt32, acl: SDLConfiguration.ACL) { self.identityId = identityId - self.acl = acl // 权限控制 let snapshotPublisher = SnapshotPublisher(initial: PolicyRuleSnapshot.empty()) self.policyRuleStore = PolicyRuleStore(publisher: snapshotPublisher) self.snapshotPublisher = snapshotPublisher + self.aclPublisher = SnapshotPublisher(initial: ExposedServiceSnapshot(acl: acl)) } nonisolated func policyRuntime() -> PolicyRuntime { - return PolicyRuntime(policyRuleSnapshot: self.snapshotPublisher.current(), flowSessionTable: self.flowSessionTable, acl: self.acl) + return PolicyRuntime(policyRuleSnapshot: self.snapshotPublisher.current(), flowSessionTable: self.flowSessionTable, acl: self.aclPublisher.current().acl) } nonisolated func recordOutboundFlow(ipPacket: IPPacketView) { @@ -65,6 +74,26 @@ actor PolicyService { await self.policyRuleStore.applyPolicyResponse(policyResponse) } + + func makeExposedServiceRequest() -> Data? { + var request = SDLExposedServiceRequest() + self.latestExposedServiceRequestVersion = Self.nextVersion(after: self.latestExposedServiceRequestVersion) + request.version = self.latestExposedServiceRequestVersion + SDLLogger.log("[PolicyService] make exposed service request, version: \(request.version)", for: .debug) + return try? request.serializedData() + } + + func applyExposedServiceResponse(_ response: SDLExposedServiceResponse) -> SDLConfiguration.ACL? { + guard response.version == self.latestExposedServiceRequestVersion else { + SDLLogger.log("[PolicyService] ignore exposed service response, version: \(response.version), latest request version: \(self.latestExposedServiceRequestVersion)", for: .debug) + return nil + } + + let acl = SDLConfiguration.ACL(response: response) + self.aclPublisher.publish(ExposedServiceSnapshot(acl: acl)) + SDLLogger.log("[PolicyService] apply exposed service response, version: \(response.version), tcp: \(acl.tcpPorts.count), udp: \(acl.udpPorts.count)", for: .debug) + return acl + } func clear() async { self.flowSessionTable.clear() @@ -74,5 +103,12 @@ actor PolicyService { deinit { SDLLogger.log("[PolicyService] deinit") } + + private static func nextVersion(after version: UInt32) -> UInt32 { + if version == UInt32.max { + return 1 + } + return version + 1 + } } diff --git a/Tun/Protobuf/SDLMessage.pb.swift b/Tun/Protobuf/SDLMessage.pb.swift index c1e2621..f894b5e 100644 --- a/Tun/Protobuf/SDLMessage.pb.swift +++ b/Tun/Protobuf/SDLMessage.pb.swift @@ -367,12 +367,21 @@ struct SDLEvent: Sendable { set {event = .shutdown(newValue)} } + var exposedServiceChanged: SDLEvent.ExposedServiceChanged { + get { + if case .exposedServiceChanged(let v)? = event {return v} + return SDLEvent.ExposedServiceChanged() + } + set {event = .exposedServiceChanged(newValue)} + } + var unknownFields = SwiftProtobuf.UnknownStorage() enum OneOf_Event: Equatable, Sendable { case natChanged(SDLEvent.NatChanged) case sendRegister(SDLEvent.SendRegister) case shutdown(SDLEvent.NetworkShutdown) + case exposedServiceChanged(SDLEvent.ExposedServiceChanged) } @@ -421,6 +430,16 @@ struct SDLEvent: Sendable { fileprivate var _v6Info: SDLV6Info? = nil } + struct ExposedServiceChanged: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + } + /// 网络关闭 struct NetworkShutdown: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the @@ -1370,6 +1389,7 @@ extension SDLEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB 1: .standard(proto: "nat_changed"), 2: .standard(proto: "send_register"), 3: .same(proto: "shutdown"), + 4: .standard(proto: "exposed_service_changed"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1417,6 +1437,19 @@ extension SDLEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB self.event = .shutdown(v) } }() + case 4: try { + var v: SDLEvent.ExposedServiceChanged? + var hadOneofValue = false + if let current = self.event { + hadOneofValue = true + if case .exposedServiceChanged(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.event = .exposedServiceChanged(v) + } + }() default: break } } @@ -1440,6 +1473,10 @@ extension SDLEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB guard case .shutdown(let v)? = self.event else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 3) }() + case .exposedServiceChanged?: try { + guard case .exposedServiceChanged(let v)? = self.event else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -1550,6 +1587,25 @@ extension SDLEvent.SendRegister: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } } +extension SDLEvent.ExposedServiceChanged: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = SDLEvent.protoMessageName + ".ExposedServiceChanged" + static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: SDLEvent.ExposedServiceChanged, rhs: SDLEvent.ExposedServiceChanged) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension SDLEvent.NetworkShutdown: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = SDLEvent.protoMessageName + ".NetworkShutdown" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ diff --git a/Tun/Protobuf/SDLMessage.swift b/Tun/Protobuf/SDLMessage.swift index 479ccff..b5ac52d 100644 --- a/Tun/Protobuf/SDLMessage.swift +++ b/Tun/Protobuf/SDLMessage.swift @@ -45,6 +45,9 @@ enum SDLPacketType: UInt8 { case policyRequest = 0xb0 case policyResponse = 0xb1 + case exposedServiceRequest = 0xb2 + case exposedServiceResponse = 0xb3 + // 获取欢迎消息 case welcome = 0x4F @@ -137,6 +140,7 @@ enum SDLQUICInboundMessage { case peerInfo(SDLPeerInfo) case event(SDLEvent) case policyReponse(SDLPolicyResponse) + case exposedServiceResponse(SDLExposedServiceResponse) case arpResponse(SDLArpResponse) } diff --git a/Tun/Super/SDLSuperCodec.swift b/Tun/Super/SDLSuperCodec.swift index d8b2c75..9c6b4ce 100644 --- a/Tun/Super/SDLSuperCodec.swift +++ b/Tun/Super/SDLSuperCodec.swift @@ -47,6 +47,12 @@ enum SDLSuperCodec { return nil } return .policyReponse(policyResponse) + case .exposedServiceResponse: + guard let bytes = buffer.readBytes(length: buffer.readableBytes), + let response = try? SDLExposedServiceResponse(serializedBytes: bytes) else { + return nil + } + return .exposedServiceResponse(response) case .arpResponse: guard let bytes = buffer.readBytes(length: buffer.readableBytes), let arpResponse = try? SDLArpResponse(serializedBytes: bytes) else {