// // SDLTunNetworkManager.swift // Tun // // Created by Codex on 2026/5/20. // import Foundation import NetworkExtension final class SDLTunNetworkManager: @unchecked Sendable { struct Settings: Sendable { let ipAddress: String let maskAddress: String let netAddress: String let networkDomain: String let shouldRouteDefault: Bool init(config: SDLConfiguration) { let networkAddress = config.networkAddress self.ipAddress = networkAddress.ipAddress self.maskAddress = networkAddress.maskAddress self.netAddress = networkAddress.netAddress self.networkDomain = networkAddress.networkDomain self.shouldRouteDefault = config.exitNode != nil } } private let provider: NEPacketTunnelProvider init(provider: NEPacketTunnelProvider) { self.provider = provider } func apply(settings: Settings, dnsServer: String) async throws { let networkSettings = self.makeNetworkSettings(settings: settings, dnsServer: dnsServer) try await self.provider.setTunnelNetworkSettings(networkSettings) } private func makeNetworkSettings(settings: Settings, dnsServer: String) -> NEPacketTunnelNetworkSettings { let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8") networkSettings.mtu = 1250 networkSettings.dnsSettings = self.makeDNSSettings(settings: settings, dnsServer: dnsServer) networkSettings.ipv4Settings = self.makeIPv4Settings(settings: settings, dnsServer: dnsServer) return networkSettings } private func makeDNSSettings(settings: Settings, dnsServer: String) -> NEDNSSettings { let dnsSettings = NEDNSSettings(servers: [dnsServer]) dnsSettings.searchDomains = [settings.networkDomain] dnsSettings.matchDomains = [settings.networkDomain, ""] // 设置为 false 允许系统在补全 Search Domain 时也能匹配到此设置 dnsSettings.matchDomainsNoSearch = false return dnsSettings } private func makeIPv4Settings(settings: Settings, dnsServer: String) -> NEIPv4Settings { let ipv4Settings = NEIPv4Settings(addresses: [settings.ipAddress], subnetMasks: [settings.maskAddress]) ipv4Settings.includedRoutes = self.makeIPv4IncludedRoutes(settings: settings, dnsServer: dnsServer) ipv4Settings.excludedRoutes = self.makeIPv4ExcludedRoutes() return ipv4Settings } private func makeIPv4IncludedRoutes(settings: Settings, dnsServer: String) -> [NEIPv4Route] { var routes: [NEIPv4Route] = [ NEIPv4Route(destinationAddress: settings.netAddress, subnetMask: settings.maskAddress), NEIPv4Route(destinationAddress: dnsServer, subnetMask: "255.255.255.255"), ] if settings.shouldRouteDefault { routes.append(.default()) } return routes } private func makeIPv4ExcludedRoutes() -> [NEIPv4Route] { let dnsServers = SDLUtil.getMacOSSystemDnsServers() var ipv4DnsServers = dnsServers.filter { !$0.contains(":") } let commonDnsServers = [ "8.8.8.8", "8.8.4.4", "223.5.5.5", "223.6.6.6", "114.114.114.114" ] for ip in commonDnsServers where !ipv4DnsServers.contains(ip) { ipv4DnsServers.append(ip) } return ipv4DnsServers.map { NEIPv4Route(destinationAddress: $0, subnetMask: "255.255.255.255") } } }