VPN initial
This commit is contained in:
@@ -1,19 +1,24 @@
|
||||
import UIKit
|
||||
import NetworkExtension
|
||||
|
||||
let VPNConfigBundleIdentifier = "de.uni-bamberg.psi.AppCheck.VPN"
|
||||
let dateFormatter = DateFormatter()
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var managerVPN: NETunnelProviderManager?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
if UserDefaults.standard.bool(forKey: "kill_proxy") {
|
||||
UserDefaults.standard.set(false, forKey: "kill_proxy")
|
||||
disableDNS()
|
||||
} else {
|
||||
postDNSState()
|
||||
}
|
||||
// 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")
|
||||
@@ -24,238 +29,92 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
try db.createTable(table: DNSQuery.self)
|
||||
} catch {}
|
||||
|
||||
// loadVPN { self.startVPN() }
|
||||
self.postVPNState(.invalid)
|
||||
loadVPN { mgr in
|
||||
self.managerVPN = mgr
|
||||
self.postVPNState()
|
||||
}
|
||||
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()
|
||||
// postVPNState()
|
||||
}
|
||||
|
||||
func setProxyEnabled(_ newState: Bool) {
|
||||
// DNS:
|
||||
if newState != managerDNS.isEnabled {
|
||||
newState ? enableDNS() : disableDNS()
|
||||
guard let mgr = self.managerVPN else {
|
||||
self.createNewVPN { manager in
|
||||
self.managerVPN = manager
|
||||
self.setProxyEnabled(newState)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 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 }
|
||||
let state = mgr.isEnabled && (mgr.connection.status == NEVPNStatus.connected)
|
||||
if state != newState {
|
||||
self.updateVPN({ mgr.isEnabled = true }) {
|
||||
newState ? try? mgr.connection.startVPNTunnel() : mgr.connection.stopVPNTunnel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func postDNSState() {
|
||||
managerDNS.loadFromPreferences {_ in
|
||||
NotificationCenter.default.post(name: .init("ChangedStateGlassDNS"), object: self.managerDNS.isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: VPN
|
||||
|
||||
/*var managerVPN: NETunnelProviderManager?
|
||||
private func createNewVPN(_ success: @escaping (_ manager: NETunnelProviderManager) -> Void) {
|
||||
let mgr = NETunnelProviderManager()
|
||||
mgr.localizedDescription = "AppCheck Monitor"
|
||||
let proto = NETunnelProviderProtocol()
|
||||
proto.providerBundleIdentifier = VPNConfigBundleIdentifier
|
||||
proto.serverAddress = "127.0.0.1"
|
||||
mgr.protocolConfiguration = proto
|
||||
mgr.isEnabled = true
|
||||
mgr.saveToPreferences { error in
|
||||
guard error == nil else { return }
|
||||
success(mgr)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadVPN(_ finally: @escaping () -> Void) {
|
||||
private func loadVPN(_ finally: @escaping (_ manager: NETunnelProviderManager?) -> 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 {
|
||||
guard let mgrs = managers, mgrs.count > 0 else {
|
||||
finally(nil)
|
||||
return
|
||||
}
|
||||
body()
|
||||
self.managerVPN?.saveToPreferences { (error) in
|
||||
guard error == nil else {
|
||||
NSLog("VPN: save error: \(String(describing: error))")
|
||||
return
|
||||
for mgr in mgrs {
|
||||
if let proto = (mgr.protocolConfiguration as? NETunnelProviderProtocol) {
|
||||
if proto.providerBundleIdentifier == VPNConfigBundleIdentifier {
|
||||
finally(mgr)
|
||||
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()
|
||||
finally(nil)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
private func updateVPN(_ body: @escaping () -> Void, _ onSuccess: @escaping () -> Void) {
|
||||
self.managerVPN?.loadFromPreferences { error in
|
||||
guard error == nil else { return }
|
||||
body()
|
||||
self.managerVPN?.saveToPreferences { error in
|
||||
guard error == nil else { return }
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
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
|
||||
private func postVPNState() {
|
||||
guard let mgr = self.managerVPN else {
|
||||
self.postVPNState(.invalid)
|
||||
return
|
||||
}
|
||||
mgr.loadFromPreferences { _ in
|
||||
self.postVPNState(mgr.connection.status)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
private func postVPNState(_ state: NEVPNStatus) {
|
||||
NotificationCenter.default.post(name: .init("ChangedStateGlassVPN"), object: state)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user