225 lines
7.2 KiB
Swift
225 lines
7.2 KiB
Swift
//
|
|
// SDLConfiguration.swift
|
|
// sdlan
|
|
//
|
|
// Created by 安礼成 on 2025/7/14.
|
|
//
|
|
import Foundation
|
|
import NIOCore
|
|
|
|
// 配置项目
|
|
public class SDLConfiguration {
|
|
|
|
// 网络地址信息
|
|
public struct NetworkAddress {
|
|
public let networkId: UInt32
|
|
public let ip: UInt32
|
|
public let maskLen: UInt8
|
|
public let mac: Data
|
|
public let networkDomain: String
|
|
|
|
// ip地址
|
|
var ipAddress: String {
|
|
return SDLUtil.int32ToIp(self.ip)
|
|
}
|
|
|
|
// 掩码
|
|
var maskAddress: String {
|
|
let len0 = 32 - maskLen
|
|
let num: UInt32 = (0xFFFFFFFF >> len0) << len0
|
|
|
|
return SDLUtil.int32ToIp(num)
|
|
}
|
|
|
|
// 网络地址
|
|
var netAddress: String {
|
|
let len0 = 32 - maskLen
|
|
let mask: UInt32 = (0xFFFFFFFF >> len0) << len0
|
|
|
|
return SDLUtil.int32ToIp(self.ip & mask)
|
|
}
|
|
}
|
|
|
|
// 网络出口
|
|
public struct ExitNode {
|
|
let exitNodeIp: UInt32
|
|
}
|
|
|
|
public struct ACL {
|
|
let tcpPorts: Set<UInt16>
|
|
let udpPorts: Set<UInt16>
|
|
|
|
static let empty = ACL(tcpPorts: [], udpPorts: [])
|
|
}
|
|
|
|
// 解析的服务器地址信息
|
|
public struct ResolvedServerEndpoint: Sendable {
|
|
let host: String
|
|
let ip: String
|
|
}
|
|
|
|
// 当前的客户端版本
|
|
let version: Int
|
|
|
|
let serverEndpoint: ResolvedServerEndpoint
|
|
|
|
let stunSocketAddress: SocketAddress
|
|
|
|
// 网络探测地址信息
|
|
let stunProbeSocketAddressArray: [[SocketAddress]]
|
|
|
|
let clientId: String
|
|
let networkAddress: NetworkAddress
|
|
let hostname: String
|
|
let accessToken: String
|
|
let identityId: UInt32
|
|
let acl: ACL
|
|
|
|
var exitNode: ExitNode?
|
|
|
|
public init(version: Int,
|
|
serverEndpoint: ResolvedServerEndpoint,
|
|
stunServers: [String],
|
|
clientId: String,
|
|
networkAddress: NetworkAddress,
|
|
hostname: String,
|
|
accessToken: String,
|
|
identityId: UInt32,
|
|
acl: ACL,
|
|
exitNode: ExitNode?) {
|
|
self.version = version
|
|
self.serverEndpoint = serverEndpoint
|
|
let stunHosts = stunServers.isEmpty ? [serverEndpoint.ip] : stunServers
|
|
self.stunSocketAddress = Self.makeStunSocketAddress(host: stunHosts[0], port: 1365)
|
|
self.stunProbeSocketAddressArray = stunHosts.map { stunServer in
|
|
[
|
|
Self.makeStunSocketAddress(host: stunServer, port: 1365),
|
|
Self.makeStunSocketAddress(host: stunServer, port: 1366)
|
|
]
|
|
}
|
|
self.clientId = clientId
|
|
self.networkAddress = networkAddress
|
|
self.accessToken = accessToken
|
|
self.identityId = identityId
|
|
self.acl = acl
|
|
self.hostname = hostname
|
|
self.exitNode = exitNode
|
|
}
|
|
|
|
}
|
|
|
|
private extension SDLConfiguration {
|
|
|
|
static func resolveHostAddress(host: String, port: Int) -> String {
|
|
let address = try! SocketAddress.makeAddressResolvingHost(host, port: port)
|
|
return address.ipAddress!
|
|
}
|
|
|
|
static func makeStunSocketAddress(host: String, port: Int) -> SocketAddress {
|
|
return try! SocketAddress.makeAddressResolvingHost(host, port: port)
|
|
}
|
|
|
|
}
|
|
|
|
// 解析配置文件
|
|
extension SDLConfiguration {
|
|
|
|
static func parse(options: [String: NSObject]) -> SDLConfiguration? {
|
|
guard let version = options["version"] as? Int,
|
|
let serverHost = options["server_host"] as? String,
|
|
let stunAssistHost = options["stun_assist_host"] as? String,
|
|
let accessToken = options["access_token"] as? String,
|
|
let identityId = options["identity_id"] as? UInt32,
|
|
let clientId = options["client_id"] as? String,
|
|
let hostname = options["hostname"] as? String,
|
|
let networkAddressDict = options["network_address"] as? [String: NSObject] else {
|
|
return nil
|
|
}
|
|
|
|
guard let networkAddress = parseNetworkAddress(networkAddressDict) else {
|
|
return nil
|
|
}
|
|
let acl = parseACL(options["acl"])
|
|
|
|
// 网络出口配置是可选的
|
|
var exitNode: ExitNode? = nil
|
|
if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
|
|
exitNode = .init(exitNodeIp: exitNodeIp)
|
|
}
|
|
|
|
let serverEndpoint = ResolvedServerEndpoint(
|
|
host: serverHost,
|
|
ip: Self.resolveHostAddress(host: serverHost, port: 1443)
|
|
)
|
|
|
|
return SDLConfiguration(version: version,
|
|
serverEndpoint: serverEndpoint,
|
|
stunServers: [serverHost, stunAssistHost],
|
|
clientId: clientId,
|
|
networkAddress: networkAddress,
|
|
hostname: hostname,
|
|
accessToken: accessToken,
|
|
identityId: identityId,
|
|
acl: acl,
|
|
exitNode: exitNode)
|
|
}
|
|
|
|
private static func parseNetworkAddress(_ config: [String: NSObject]) -> SDLConfiguration.NetworkAddress? {
|
|
guard let networkId = config["network_id"] as? UInt32,
|
|
let ipStr = config["ip"] as? String,
|
|
let ip = SDLUtil.ipv4StrToInt32(ipStr),
|
|
let maskLen = config["mask_len"] as? UInt8,
|
|
let mac = config["mac"] as? Data,
|
|
let networkDomain = config["network_domain"] as? String else {
|
|
return nil
|
|
}
|
|
|
|
return .init(networkId: networkId, ip: ip, maskLen: maskLen, mac: mac, networkDomain: networkDomain)
|
|
}
|
|
|
|
private static func parseACL(_ value: NSObject?) -> SDLConfiguration.ACL {
|
|
guard let dict = value as? [String: NSObject] else {
|
|
return .empty
|
|
}
|
|
|
|
return .init(
|
|
tcpPorts: parsePortSet(dict["tcp"]),
|
|
udpPorts: parsePortSet(dict["udp"])
|
|
)
|
|
}
|
|
|
|
private static func parsePortSet(_ value: NSObject?) -> Set<UInt16> {
|
|
let ports: [UInt32]
|
|
if let values = value as? [UInt32] {
|
|
ports = values
|
|
} else if let values = value as? [Int] {
|
|
ports = values.compactMap { $0 >= 0 ? UInt32($0) : nil }
|
|
} else if let values = value as? [NSNumber] {
|
|
ports = values.map(\.uint32Value)
|
|
} else if let values = value as? NSArray {
|
|
ports = values.compactMap { item in
|
|
if let value = item as? UInt32 {
|
|
return value
|
|
}
|
|
if let value = item as? Int, value >= 0 {
|
|
return UInt32(value)
|
|
}
|
|
if let value = item as? NSNumber {
|
|
return value.uint32Value
|
|
}
|
|
return nil
|
|
}
|
|
} else {
|
|
ports = []
|
|
}
|
|
|
|
return Set(ports.compactMap { port in
|
|
guard port > 0, port <= UInt32(UInt16.max) else {
|
|
return nil
|
|
}
|
|
return UInt16(port)
|
|
})
|
|
}
|
|
|
|
}
|