115 lines
4.2 KiB
Swift
115 lines
4.2 KiB
Swift
//
|
|
// PolicyService.swift
|
|
// punchnet
|
|
//
|
|
// Created by 安礼成 on 2026/5/19.
|
|
//
|
|
|
|
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<PolicyRuleSnapshot>
|
|
nonisolated private let aclPublisher: SnapshotPublisher<ExposedServiceSnapshot>
|
|
|
|
nonisolated private let flowSessionTable = FlowSessionTable()
|
|
|
|
// 当前节点的identityId值
|
|
let identityId: UInt32
|
|
private var latestExposedServiceRequestVersion: UInt32 = 0
|
|
|
|
init(identityId: UInt32, acl: SDLConfiguration.ACL) {
|
|
self.identityId = identityId
|
|
// 权限控制
|
|
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.aclPublisher.current().acl)
|
|
}
|
|
|
|
nonisolated func recordOutboundFlow(ipPacket: IPPacketView) {
|
|
guard let flowSession = ipPacket.flowSession() else {
|
|
return
|
|
}
|
|
|
|
switch ipPacket.transportPacket {
|
|
case .tcp(_, _, let flags):
|
|
self.flowSessionTable.recordOutboundTCP(flowSession, flags: flags)
|
|
case .udp(_, let dstPort, _):
|
|
self.flowSessionTable.recordOutboundUDP(flowSession, isDNS: dstPort == 53)
|
|
default:
|
|
return
|
|
}
|
|
}
|
|
|
|
func makePolicyRequest(srcIdentityID: UInt32) async -> Data? {
|
|
return await self.policyRuleStore.makePolicyRequest(srcIdentityId: srcIdentityID, dstIdentityId: self.identityId)
|
|
}
|
|
|
|
func updatePolicy(superServiceProxy: SDLSuperServiceProxy) async {
|
|
let requests = await self.policyRuleStore.makeBatchPolicyRequests(dstIdentityID: self.identityId)
|
|
for request in requests {
|
|
await superServiceProxy.send(type: .policyRequest, data: request)
|
|
}
|
|
}
|
|
|
|
func applyPolicyResponse(_ policyResponse: SDLPolicyResponse) async {
|
|
guard policyResponse.dstIdentityID == self.identityId else {
|
|
SDLLogger.log("[PolicyService] ignore policy response, dstIdentityID mismatch: \(policyResponse.dstIdentityID), expected: \(self.identityId)", for: .debug)
|
|
return
|
|
}
|
|
|
|
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()
|
|
await self.policyRuleStore.clear()
|
|
}
|
|
|
|
deinit {
|
|
SDLLogger.log("[PolicyService] deinit")
|
|
}
|
|
|
|
private static func nextVersion(after version: UInt32) -> UInt32 {
|
|
if version == UInt32.max {
|
|
return 1
|
|
}
|
|
return version + 1
|
|
}
|
|
|
|
}
|