user3769499
user3769499

Reputation: 65

How can I change wifi DNS setting iOS using swift

I am trying my best to get this working.

I have a DNS server for my clients where sometimes I send them emails to chnage their DNS Settings. But now I want to do that via an ios app. is there a way I can let them download the app and click one button on the app that will chnage it ?

I looked at this https://developer.apple.com/library/ios/documentation/NetworkExtension/Reference/NEDNSSettingsClassRef/index.html#//apple_ref/occ/cl/NEDNSSettings

but unsure

THanks

Upvotes: 0

Views: 5289

Answers (2)

Chandra
Chandra

Reputation: 379

Please consider building a DNSProxy Extension(one of the Network Extension) to intercept all DNS traffic generated on a device and use custom/Internal DNS servers.

Upvotes: 0

Popmedic
Popmedic

Reputation: 1871

Look at the Network Extensions classes. With the NETunnelProviderManager class you can set the onDemandRules with a NEEvaluateConnectionRule. The NEEvaluateConnectionRule constructor can take a list of wildcard with top-level-domains (i.e. ["*.com", "*.net", "*.org", "*.io"]) as the domains, and use NEEvaluateConnectionRuleAction.connectIfNeeded as the action. Set the onDemandRules of the NEEvaluateConnectionRule you create with all tlds as the domains. Then create a NEOnDemandRuleEvaluateConnection and set its connectionRules to the NEEvaluateConnectionRule created with all of the top-level-domains, and set its interfaceTypeMatch to NEOnDemandRuleInterfaceType.any. Set the NETunnelProviderManager.onDemandRules with a NEOnDemandRuleEvaluateConnection created this way. If you create a NETunnelProviderManagerand load it and save it as described above, you can then turn it on and off by using the NETunnelProviderManager.isEnabled and NETunnelProviderManager.isOnDemandEnabled properties.

Here is an example class that does exactly that.

import Foundation
import NetworkExtension

public class VPNConnect {
    private static let vpnDescription = "DNS OnDemand to GoogleDNS"
    private static let vpnServerDescription = "OnDemand DNS to GoogleDNS"

    public var manager:NETunnelProviderManager = NETunnelProviderManager()
    public var dnsEndpoint1:String = "8.8.8.8"
    public var dnsEndpoint2:String = "8.8.4.4"

    public var connected:Bool {
        get {
            return self.manager.isOnDemandEnabled
        }
        set {
            if newValue != self.connected {
                update(
                    body: {
                        self.manager.isEnabled = newValue
                        self.manager.isOnDemandEnabled = newValue

                    },
                    complete: {
                        if newValue {
                            do {
                                try (self.manager.connection as? NETunnelProviderSession)?.startVPNTunnel(options: nil)
                            } catch let err as NSError {
                                NSLog("\(err.localizedDescription)")
                            }
                        } else {
                            (self.manager.connection as? NETunnelProviderSession)?.stopVPNTunnel()
                        }
                    }
                )
            }
        }
    }

    public init() {
        refreshManager()
    }

    public func refreshManager() -> Void {
        NETunnelProviderManager.loadAllFromPreferences(completionHandler: { (managers, error) in
            if nil == error {
                if let managers = managers {
                    for manager in managers {
                        if manager.localizedDescription == VPNConnect.vpnDescription {
                            self.manager = manager
                            return
                        }
                    }
                }
            }
            self.setPreferences()
        })
    }

    private func update(body: @escaping ()->Void, complete: @escaping ()->Void) {
        manager.loadFromPreferences { error in
            if (error != nil) {
                NSLog("Load error: \(String(describing: error?.localizedDescription))")
                return
            }            
            body()
            self.manager.saveToPreferences { (error) in
                if nil != error {
                    NSLog("vpn_connect: save error \(error!)")
                } else {
                    complete()
                }
            }
        }
    }

    private func setPreferences() {
        self.manager.localizedDescription = VPNConnect.vpnDescription        
        let proto = NETunnelProviderProtocol()
        proto.providerBundleIdentifier = "com.popmedic.vpntunnel.provider"
        proto.serverAddress = VPNConnect.vpnServerDescription
        self.manager.protocolConfiguration = proto
        // TLDList is a struct I created in its own swift file that has an array of all top level domains
        let evaluationRule = NEEvaluateConnectionRule(matchDomains: TLDList.tlds, 
                                                         andAction: NEEvaluateConnectionRuleAction.connectIfNeeded)
        evaluationRule.useDNSServers = [self.dnsEndpoint1, self.dnsEndpoint2]
        let onDemandRule = NEOnDemandRuleEvaluateConnection()
        onDemandRule.connectionRules = [evaluationRule]
        onDemandRule.interfaceTypeMatch = NEOnDemandRuleInterfaceType.any
        self.manager.onDemandRules = [onDemandRule]
    }
}

Please note that you will have to turn the Network Extensions capabilities on and there will be a dialog presented telling the user that you are turning on a VPN connection, but you will not have the [VPN] icon in the status bar when the connection is turned on because we are not setting a vpn, just using the on demand rules.

Hate Google as much as I do, maybe use this for the DNS you set... Quad9

Upvotes: 2

Related Questions