128 lines
4.0 KiB
Swift
128 lines
4.0 KiB
Swift
//
|
||
// Util.swift
|
||
// Tun
|
||
//
|
||
// Created by 安礼成 on 2024/1/19.
|
||
//
|
||
|
||
import Foundation
|
||
import SystemConfiguration
|
||
import Network
|
||
import Darwin
|
||
|
||
struct SDLUtil {
|
||
|
||
public static func int32ToIp(_ num: UInt32) -> String {
|
||
let ip0 = (UInt8) (num >> 24 & 0xFF)
|
||
let ip1 = (UInt8) (num >> 16 & 0xFF)
|
||
let ip2 = (UInt8) (num >> 8 & 0xFF)
|
||
let ip3 = (UInt8) (num & 0xFF)
|
||
|
||
return "\(ip0).\(ip1).\(ip2).\(ip3)"
|
||
}
|
||
|
||
public static func netMaskIp(maskLen: UInt8) -> String {
|
||
let len0 = 32 - maskLen
|
||
let num: UInt32 = (0xFFFFFFFF >> len0) << len0
|
||
|
||
let ip0 = (UInt8) (num >> 24 & 0xFF)
|
||
let ip1 = (UInt8) (num >> 16 & 0xFF)
|
||
let ip2 = (UInt8) (num >> 8 & 0xFF)
|
||
let ip3 = (UInt8) (num & 0xFF)
|
||
|
||
return "\(ip0).\(ip1).\(ip2).\(ip3)"
|
||
}
|
||
|
||
public static func ipv4StrToInt32(_ ip: String) -> UInt32? {
|
||
let parts = ip.split(separator: ".")
|
||
guard parts.count == 4 else {
|
||
return nil
|
||
}
|
||
|
||
var result: UInt32 = 0
|
||
for part in parts {
|
||
guard let byte = UInt8(part) else { return nil }
|
||
result = (result << 8) | UInt32(byte)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
public static func ipv6DataToString(_ data: Data) -> String? {
|
||
guard data.count == 16 else {
|
||
return nil
|
||
}
|
||
|
||
return data.withUnsafeBytes { rawBuffer in
|
||
guard let baseAddress = rawBuffer.baseAddress else {
|
||
return nil
|
||
}
|
||
|
||
var hostBuffer = [CChar](repeating: 0, count: Int(INET6_ADDRSTRLEN))
|
||
guard inet_ntop(AF_INET6, baseAddress, &hostBuffer, socklen_t(INET6_ADDRSTRLEN)) != nil else {
|
||
return nil
|
||
}
|
||
|
||
return String(cString: hostBuffer)
|
||
}
|
||
}
|
||
|
||
// 判断ip地址是否在同一个网络
|
||
public static func inSameNetwork(ip: UInt32, compareIp: UInt32, maskLen: UInt8) -> Bool {
|
||
if ip == compareIp {
|
||
return true
|
||
}
|
||
|
||
let len0 = 32 - maskLen
|
||
// 掩码值
|
||
let mask: UInt32 = (0xFFFFFFFF >> len0) << len0
|
||
|
||
return ip & mask == compareIp & mask
|
||
}
|
||
|
||
public static func formatMacAddress(mac: Data) -> String {
|
||
let bytes = [UInt8](mac)
|
||
|
||
return bytes.map { String(format: "%02X", $0) }.joined(separator: ":").lowercased()
|
||
}
|
||
|
||
public static func getMacOSSystemDnsServers() -> [String] {
|
||
var results = [String]()
|
||
|
||
// 获取全局 DNS 配置
|
||
if let dict = SCDynamicStoreCopyValue(nil, "State:/Network/Global/DNS" as CFString) as? [String: Any] {
|
||
if let servers = dict["ServerAddresses"] as? [String] {
|
||
results = servers
|
||
}
|
||
}
|
||
return results
|
||
}
|
||
|
||
// 域名解析
|
||
static func resolveHostname(host: String) async -> String? {
|
||
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(host), port: 53)
|
||
let parameters = NWParameters.udp
|
||
// 即使还没正式开始,也加上这个,确保不会被残留的旧 utun 路由卡死
|
||
parameters.prohibitedInterfaceTypes = [.other]
|
||
|
||
let connection = NWConnection(to: endpoint, using: parameters)
|
||
|
||
return await withCheckedContinuation { continuation in
|
||
connection.stateUpdateHandler = { state in
|
||
if case .ready = state {
|
||
if let path = connection.currentPath,
|
||
case .hostPort(let resolvedHost, _) = path.remoteEndpoint {
|
||
let ip = String(describing: resolvedHost)
|
||
continuation.resume(returning: ip)
|
||
connection.cancel()
|
||
}
|
||
} else if case .failed = state {
|
||
continuation.resume(returning: nil)
|
||
}
|
||
}
|
||
connection.start(queue: .global())
|
||
}
|
||
}
|
||
|
||
}
|