// // VPNManager.swift // sdlan // // Created by 安礼成 on 2024/1/17. // import Foundation import NetworkExtension import SwiftUI // vpn管理类 class VPNManager: ObservableObject { static let shared = VPNManager() @Published var vpnStatus: VPNStatus = .disconnected @Published var title: String = "启动" @Published var color: Color = .white enum VPNStatus { case connected case disconnected } private init() { } // 开启vpn func enableVpn(options: [String : NSObject]? = nil) async throws { let manager = try await loadAndCreateProviderManager() try await manager.loadFromPreferences() self.addVPNStatusObserver(manager) try manager.connection.startVPNTunnel(options: options) } // 关闭vpn func disableVpn() async throws { let managers = try await NETunnelProviderManager.loadAllFromPreferences() managers.first?.connection.stopVPNTunnel() } // MARK: - Private Methods // 监控系统VPN的状态的变化 private func addVPNStatusObserver(_ manager: NETunnelProviderManager) { NotificationCenter.default.removeObserver(self) NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: manager.connection, queue: .main) { [unowned self] (notification) -> Void in // 更新vpn的状态 switch manager.connection.status { case .invalid, .disconnected, .disconnecting: self.vpnStatus = .disconnected self.title = "启动" self.color = .white case .connecting, .connected, .reasserting: self.vpnStatus = .connected self.title = "停止" self.color = .red @unknown default: self.vpnStatus = .disconnected self.title = "启动" self.color = .red } } } // MARK: - Private Methods // 加载或者创建相关的配置 private func loadAndCreateProviderManager() async throws -> NETunnelProviderManager { let managers = try await NETunnelProviderManager.loadAllFromPreferences() let manager = managers.first ?? NETunnelProviderManager() manager.localizedDescription = "sdlan" manager.isEnabled = true // 设置相关参数,在PacketTunnel中可以用 let protocolConfiguration = NETunnelProviderProtocol() protocolConfiguration.serverAddress = "sdlan" protocolConfiguration.providerConfiguration = [String:AnyObject]() protocolConfiguration.providerBundleIdentifier = "com.jihe.sdlan.Tun" manager.protocolConfiguration = protocolConfiguration manager.isOnDemandEnabled = false manager.isEnabled = true try await manager.saveToPreferences() return manager } deinit { NotificationCenter.default.removeObserver(self) } }