70 lines
2.7 KiB
Swift
70 lines
2.7 KiB
Swift
import Darwin
|
||
import Foundation
|
||
import Localization
|
||
|
||
/// 常用公共 DNS。只用 IPv4 地址:没有 IPv6 的网络里写入 IPv6 服务器会拖慢解析
|
||
public enum DNSPreset: String, CaseIterable, Identifiable, Sendable {
|
||
case automatic, cloudflare, google, tencent, aliyun
|
||
|
||
public var id: String { rawValue }
|
||
|
||
public var title: String {
|
||
switch self {
|
||
case .automatic: tr("自动")
|
||
case .cloudflare: "Cloudflare"
|
||
case .google: "Google"
|
||
case .tencent: tr("腾讯 DNSPod")
|
||
case .aliyun: tr("阿里云")
|
||
}
|
||
}
|
||
|
||
public var servers: [String] {
|
||
switch self {
|
||
case .automatic: []
|
||
case .cloudflare: ["1.1.1.1", "1.0.0.1"]
|
||
case .google: ["8.8.8.8", "8.8.4.4"]
|
||
case .tencent: ["119.29.29.29", "182.254.116.116"]
|
||
case .aliyun: ["223.5.5.5", "223.6.6.6"]
|
||
}
|
||
}
|
||
|
||
/// 当前手动设置的地址与哪个预设一致;无手动地址即“自动”
|
||
public static func matching(_ servers: [String]) -> DNSPreset? {
|
||
allCases.first { $0.servers == servers }
|
||
}
|
||
}
|
||
|
||
public enum DNSConfiguration {
|
||
public static let maxServers = 6
|
||
|
||
/// 只接受数字形式的 IPv4 / IPv6 地址
|
||
public static func isValidAddress(_ text: String) -> Bool {
|
||
var v4 = in_addr()
|
||
var v6 = in6_addr()
|
||
return inet_pton(AF_INET, text, &v4) == 1 || inet_pton(AF_INET6, text, &v6) == 1
|
||
}
|
||
|
||
/// 把用户输入(逗号、空格或换行分隔)拆成地址列表;有无效地址时返回 nil
|
||
public static func parse(_ input: String) -> [String]? {
|
||
let parts = input.split { $0 == "," || $0 == "," || $0.isWhitespace }.map(String.init)
|
||
guard parts.count <= maxServers, parts.allSatisfy(isValidAddress) else { return nil }
|
||
return parts
|
||
}
|
||
|
||
/// 服务名来自系统,可能包含空格或引号;只拒绝控制字符
|
||
public static func isValidServiceName(_ name: String) -> Bool {
|
||
!name.isEmpty && name.count <= 128 && !name.unicodeScalars.contains { CharacterSet.controlCharacters.contains($0) }
|
||
}
|
||
|
||
public static func networksetupArguments(service: String, servers: [String]) -> [String] {
|
||
["-setdnsservers", service] + (servers.isEmpty ? ["Empty"] : servers)
|
||
}
|
||
|
||
/// 未安装辅助工具时通过管理员授权执行的 shell 命令。服务名按单引号转义,地址已校验为纯数字形式
|
||
public static func shellCommand(service: String, servers: [String]) -> String {
|
||
let quoted = "'" + service.replacingOccurrences(of: "'", with: "'\\''") + "'"
|
||
let arguments = ["-setdnsservers", quoted] + (servers.isEmpty ? ["Empty"] : servers)
|
||
return (["/usr/sbin/networksetup"] + arguments).joined(separator: " ")
|
||
}
|
||
}
|