import UIKit import NetworkExtension @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { if UserDefaults.standard.bool(forKey: "kill_proxy") { UserDefaults.standard.set(false, forKey: "kill_proxy") disableDNS() } else { postDNSState() } if UserDefaults.standard.bool(forKey: "kill_db") { UserDefaults.standard.set(false, forKey: "kill_db") SQLiteDatabase.destroyDatabase(path: DB_PATH) } do { let db = try SQLiteDatabase.open(path: DB_PATH) try db.createTable(table: DNSQuery.self) } catch {} // loadVPN { self.startVPN() } return true } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. postDNSState() } func setProxyEnabled(_ newState: Bool) { // DNS: if newState != managerDNS.isEnabled { newState ? enableDNS() : disableDNS() } // VPN: // let con = self.managerVPN?.connection // if newState != (con?.status == NEVPNStatus.connected) { // self.updateVPN { // self.managerVPN?.isEnabled = newState // newState ? try? con?.startVPNTunnel() : con?.stopVPNTunnel() // } // } } // MARK: DNS let managerDNS = NEDNSProxyManager.shared() private func enableDNS() { updateDNS { self.managerDNS.localizedDescription = "GlassDNS" let proto = NEDNSProxyProviderProtocol() proto.providerBundleIdentifier = "de.uni-bamberg.psi.AppCheck.DNS" self.managerDNS.providerProtocol = proto self.managerDNS.isEnabled = true } } private func disableDNS() { updateDNS { self.managerDNS.isEnabled = false } } private func updateDNS(_ body: @escaping () -> Void) { managerDNS.loadFromPreferences { (error) in guard error == nil else { return } body() self.managerDNS.saveToPreferences { (error) in self.postDNSState() guard error == nil else { return } } } } private func postDNSState() { managerDNS.loadFromPreferences {_ in NotificationCenter.default.post(name: .init("ChangedStateGlassDNS"), object: self.managerDNS.isEnabled) } } // MARK: VPN /*var managerVPN: NETunnelProviderManager? private func loadVPN(_ finally: @escaping () -> Void) { NETunnelProviderManager.loadAllFromPreferences { managers, error in if managers?.count ?? 0 > 0 { managers?.forEach({ mgr in if let proto = (mgr.protocolConfiguration as? NETunnelProviderProtocol) { if proto.providerBundleIdentifier == "de.uni-bamberg.psi.AppCheck.Tunnel" { // self.managerVPN = mgr mgr.removeFromPreferences() } } }) } if self.managerVPN != nil { finally() } else { let mgr = NETunnelProviderManager() mgr.localizedDescription = "GlassTunnel" let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = "de.uni-bamberg.psi.AppCheck.Tunnel" proto.serverAddress = "127.0.0.1" // proto.username = "none" // proto.proxySettings = NEProxySettings() // proto.proxySettings?.httpEnabled = true // proto.proxySettings?.httpsEnabled = true // proto.authenticationMethod = .sharedSecret // proto.sharedSecretReference = try! VPNKeychain.persistentReferenceFor(service: "GlassTunnel", account:"none", password: "none".data(using: String.Encoding.utf8)!) mgr.protocolConfiguration = proto mgr.isEnabled = true self.managerVPN = mgr mgr.saveToPreferences { (error) in guard error == nil else { NSLog("VPN: save error: \(String(describing: error))") return } finally() } } } } private func startVPN() { updateVPN { do { try self.managerVPN?.connection.startVPNTunnel() } catch { print("VPN: start error: \(error.localizedDescription)") } } } private func updateVPN(_ body: @escaping () -> Void) { self.managerVPN?.loadFromPreferences { (error) in guard error == nil else { return } body() self.managerVPN?.saveToPreferences { (error) in guard error == nil else { NSLog("VPN: save error: \(String(describing: error))") return } } } }*/ } // MARK: VPNKeychain /* /// Utility routines for working with the keychain. enum VPNKeychain { /// Returns a persistent reference for a generic password keychain item, adding it to /// (or updating it in) the keychain if necessary. /// /// This delegates the work to two helper routines depending on whether the item already /// exists in the keychain or not. /// /// - Parameters: /// - service: The service name for the item. /// - account: The account for the item. /// - password: The desired password. /// - Returns: A persistent reference to the item. /// - Throws: Any error returned by the Security framework. static func persistentReferenceFor(service: String, account: String, password: Data) throws -> Data { var copyResult: CFTypeRef? = nil let err = SecItemCopyMatching([ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecReturnPersistentRef: true, kSecReturnData: true ] as NSDictionary, ©Result) switch err { case errSecSuccess: return try self.persistentReferenceByUpdating(copyResult: copyResult!, service: service, account: account, password: password) case errSecItemNotFound: return try self.persistentReferenceByAdding(service: service, account:account, password: password) default: try throwOSStatus(err) // `throwOSStatus(_:)` only returns in the `errSecSuccess` case. We know we're // not in that case but the compiler can't figure that out, alas. fatalError() } } /// Returns a persistent reference for a generic password keychain item by updating it /// in the keychain if necessary. /// /// - Parameters: /// - copyResult: The result from the `SecItemCopyMatching` done by `persistentReferenceFor(service:account:password:)`. /// - service: The service name for the item. /// - account: The account for the item. /// - password: The desired password. /// - Returns: A persistent reference to the item. /// - Throws: Any error returned by the Security framework. private static func persistentReferenceByUpdating(copyResult: CFTypeRef, service: String, account: String, password: Data) throws -> Data { let copyResult = copyResult as! [String:Any] let persistentRef = copyResult[kSecValuePersistentRef as String] as! NSData as Data let currentPassword = copyResult[kSecValueData as String] as! NSData as Data if password != currentPassword { let err = SecItemUpdate([ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, ] as NSDictionary, [ kSecValueData: password ] as NSDictionary) try throwOSStatus(err) } return persistentRef } /// Returns a persistent reference for a generic password keychain item by adding it to /// the keychain. /// /// - Parameters: /// - service: The service name for the item. /// - account: The account for the item. /// - password: The desired password. /// - Returns: A persistent reference to the item. /// - Throws: Any error returned by the Security framework. private static func persistentReferenceByAdding(service: String, account: String, password: Data) throws -> Data { var addResult: CFTypeRef? = nil let err = SecItemAdd([ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecValueData: password, kSecReturnPersistentRef: true, ] as NSDictionary, &addResult) try throwOSStatus(err) return addResult! as! NSData as Data } /// Throws an error if a Security framework call has failed. /// /// - Parameter err: The error to check. private static func throwOSStatus(_ err: OSStatus) throws { guard err == errSecSuccess else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil) } } } */