punchnet-macos/Tun/TunNetwork/SDLTunNetworkManager.swift
2026-05-21 14:39:41 +08:00

97 lines
3.5 KiB
Swift

//
// 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")
}
}
}