DNS Proxy Network Extension startProxy

I'm trying to get a DNS Proxy working in iOS 11.0 beta 2. I have the entitlements, and I have enabled the DNS proxy through the manager but it isn't calling startProxy in my Proxy Provider. I'm able to loadFromPreferences() so I think the entitlements are correct and isEnabled shows true when I move the app to the background and back to the foreground. Any help would be great.


In my main app:


func applicationDidBecomeActive(_ application: UIApplication) {

let manager = NEDNSProxyManager.shared()

if manager.isEnabled == true {

NSLog("enabled")

} else {

manager.localizedDescription = "DNS Proxy"

manager.loadFromPreferences { error in

if (error != nil) {

NSLog("Load error: \(String(describing: error?.localizedDescription))");

} else {

NSLog("loaded preferences");

let dict = ["foo": "bar"]

let proto = NEDNSProxyProviderProtocol()

proto.providerConfiguration = dict

proto.providerBundleIdentifier = "com.bangj.DNS.DNS-Proxy"

manager.providerProtocol = proto

manager.isEnabled = true

}

}

}

}


My Proxy Provider:


class DNSProxyProvider: NEDNSProxyProvider {

override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {

NSLog("startproxy")

/

completionHandler(nil)

}


override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {

NSLog("stopproxy")

/

completionHandler()

}


override func sleep(completionHandler: @escaping () -> Void) {

NSLog("sleep")

/

completionHandler()

}


override func wake() {

NSLog("wake")

/

}


override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {

NSLog("handleNewFlow")

/

return false

}

}


I think my entitlements look good:


butte% codesign -d --entitlements :- DNS-Proxy.appex

Executable=/Users/pusateri/Library/Developer/Xcode/DerivedData/DNS-grgoqerfsmhphqfyrpxzgzxiqdkd/Build/Products/Debug-iphoneos/DNS-Proxy.appex/DNS-Proxy

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-/

<plist version="1.0">

<dict>

<key>application-identifier</key>

<string>XXXXXXXXXX.com.bangj.DNS.DNS-Proxy</string>

<key>com.apple.developer.networking.networkextension</key>

<array>

<string>dns-proxy</string>

</array>

<key>com.apple.developer.team-identifier</key>

<string>XXXXXXXXXX</string>

<key>com.apple.security.application-groups</key>

<array>

<string>group.com.bangj.DNS</string>

</array>

<key>get-task-allow</key>

<true/>

</dict>

</plist>


% codesign -d --entitlements :- DNS.app

Executable=/Users/pusateri/Library/Developer/Xcode/DerivedData/DNS-grgoqerfsmhphqfyrpxzgzxiqdkd/Build/Products/Debug-iphoneos/DNS.app/DNS

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-/

<plist version="1.0">

<dict>

<key>application-identifier</key>

<string>XXXXXXXXXX.com.bangj.DNS</string>

<key>com.apple.developer.networking.networkextension</key>

<array>

<string>dns-proxy</string>

</array>

<key>com.apple.developer.team-identifier</key>

<string>XXXXXXXXXX</string>

<key>get-task-allow</key>

<true/>

</dict>

</plist>


One thing that is confusing is that in NEDNSProxyManager.h, enabled is the property but I can't set enabled in Xcode. I have to use isEnabled even though it's just the getter (and not the setter). I'm new to Swift so maybe I don't understand how setters work in Swift. setEnabled doesn't work either.


/!

* @property enabled

* @discussion Toggles the enabled status of the DNS proxy. Setting this property will disable DNS proxy configurations of other apps. This property will be set to NO when other DNS proxy configurations are enabled.

*/

@property (getter=isEnabled) BOOL enabled NS_AVAILABLE(NA, 11_0);


One more thing, this is probably a beta thing but NEDNS Proxy doesn't seem to be available for macos, just iOS.


I'm running this on a real phone. No configuration profile. And, yes, wifi debugging is AWESOME!

Answered by DTS Engineer in 246229022

I only had a short amount of time to play with this today but I did manage to get the provider loading. I’m going to address some specific points in your original post and then describe what I did.

You wrote:

I'm able to loadFromPreferences() …

Did you actually call

saveToPreferences(completionHandler:)
? I don’t see that anywhere in the snippets you posted.

I think my entitlements look good:

You should dump the entitlements of the

.appex
inside your
.app
, rather than the one at the top level of your build results folder. That ensures that you’re dumping the entitlements that are actually being looked at by iOS.

You should also dump your provisioning profiles to ensure that they whitelist the entitlements you use (specifically

com.apple.developer.networking.networkextension
).

One thing that is confusing is that in NEDNSProxyManager.h,

enabled
is the property but I can't set
enabled
in Xcode.

Right. That’s a Swift thing. In Objective-C you have the

isEnabled
getter paired to the
enabled
setter, but Swift exposes both as
isEnabled
so as to conform to standard Swift style.

NEDNS Proxy doesn't seem to be available for macos, just iOS.

Correct.

So, I sat down to play with this API today and managed to get it to the point where the provider actually loads and

startProxy(options:completionHandler:)
is called. My provider looks very much like yours. The only change I made was to delete extraneous stuff.
import NetworkExtension

class DNSProxyProvider: NEDNSProxyProvider {

    override init() {
        NSLog("QNEDNSProxy.Provider: init")
        super.init()
        // +++ might want to set up KVO on `systemDNSSettings`
    }

    override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
        NSLog("QNEDNSProxy.Provider: start")
        completionHandler(nil)
    }

    override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
        NSLog("QNEDNSProxy.Provider: stop")
        completionHandler()
    }

    override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
        NSLog("QNEDNSProxy.Provider: new flow (denied)")
        return false
    }
}

Note that all my log messages include QNEDNSProxy, which helps when it comes to debugging (more on this below).

My loading code is also very similar to yours:

private func enable() {
    self.update {
        self.manager.localizedDescription = "QNEDNSProxy Test"
        let proto = NEDNSProxyProviderProtocol()
        // proto.providerConfiguration = +++
        proto.providerBundleIdentifier = "com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider"
        self.manager.providerProtocol = proto
        self.manager.isEnabled = true
    }
}

private func disable() {
    self.update {
        self.manager.isEnabled = false
    }
}

private func update(_ body: @escaping () -> Void) {
    self.manager.loadFromPreferences { (error) in
        guard error == nil else {
            NSLog("QNEDNSProxy.App: load error")
            return
        }
        body()
        self.manager.saveToPreferences { (error) in
            guard error == nil else {
                NSLog("QNEDNSProxy.App: save error")
                return
            }
            NSLog("QNEDNSProxy.App: saved")
        }
    }
}

Note that I’m calling

saveToPreferences(completionHandler:)
, which is required per my comments above.

Beyond that it was just a question getting the provisioning and entitlements correct. I’ve pasted in dumps of those at the end of this email.

IMPORTANT The app group is not needed for this minimal example. It was inherited from the Network Extension template, which includes it because it’s probably going to be useful in the long term.

Finally, some debugging hints. I wired up the

enable()
and
disable()
methods to buttons in my test app. I then ran the Console utility on my Mac and selected my iPhone on the left. I then entered QNEDNSProxy into the search field so that I see all messages related to be app and its provider. At that point I could see the system make progress as it tried to load my provider. When things started to go wrong — for example, when I saw messages about the state changing from ‘starting’ to ‘stopping’ — I removed the QNEDNSProxy search term and started looking at all the messages that were likely to be related to this task. I eventually found a log message from
pkd
(the daemon responsible for PlugInKit, the infrastructure used by app extensions) which indicated that I had set
providerBundleIdentifier
incorrectly.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
$ codesign -d --entitlements :- QNEDNSProxy.app/PlugIns/Provider.appex
Executable=/Users/quinn/DTS Work iOS/Samples and Tests/QNE/QNEDNSProxy-GIT/build/Debug-iphoneos/QNEDNSProxy.app/PlugIns/Provider.appex/Provider
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
    <key>com.apple.developer.networking.networkextension</key>
    <array>
        <string>dns-proxy</string>
    </array>
    <key>com.apple.developer.team-identifier</key>
    <string>VR9NTVC6BB</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.apple-samplecode.QNE-iOS</string>
    </array>
    <key>get-task-allow</key>
    <true/>
</dict>
</plist>
$ 
$ codesign -d --entitlements :- QNEDNSProxy.app/PlugIns/Provider.appex
Executable=/Users/quinn/DTS Work iOS/Samples and Tests/QNE/QNEDNSProxy-GIT/build/Debug-iphoneos/QNEDNSProxy.app/PlugIns/Provider.appex/Provider
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
    <key>com.apple.developer.networking.networkextension</key>
    <array>
        <string>dns-proxy</string>
    </array>
    <key>com.apple.developer.team-identifier</key>
    <string>VR9NTVC6BB</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.apple-samplecode.QNE-iOS</string>
    </array>
    <key>get-task-allow</key>
    <true/>
</dict>
</plist>
$
$ security cms -D -i QNEDNSProxy.app/embedded.mobileprovision 
…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>AppIDName</key>
    <string>QNE iOS DNSProxy</string>
    <key>ApplicationIdentifierPrefix</key>
    <array>
    <string>VR9NTVC6BB</string>
    </array>
    <key>CreationDate</key>
    <date>2017-07-19T11:01:01Z</date>
    <key>Platform</key>
    <array>
        <string>iOS</string>
    </array>
    <key>DeveloperCertificates</key>
    <array>
        …
    </array>
    <key>Entitlements</key>
    <dict>
        <key>com.apple.developer.networking.networkextension</key>
        <array> 
            <string>app-proxy-provider</string> 
            <string>content-filter-provider</string> 
            <string>packet-tunnel-provider</string>
            <string>dns-proxy</string>
        </array>
        <key>keychain-access-groups</key>
        <array>
            <string>VR9NTVC6BB.*</string>       
        </array>
        <key>get-task-allow</key>
        <true/>
        <key>application-identifier</key>
        <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy</string>
        <key>com.apple.security.application-groups</key>
        <array>
            <string>group.com.example.apple-samplecode.QNE-iOS</string>
        </array>
        <key>com.apple.developer.team-identifier</key>
        <string>VR9NTVC6BB</string>
    </dict>
    <key>ExpirationDate</key>
    <date>2018-07-19T11:01:01Z</date>
    <key>Name</key>
    <string>QNE iOS DNSProxy</string>
    <key>ProvisionedDevices</key>
    <array>
        …
    </array>
    <key>TeamIdentifier</key>
    <array>
        <string>VR9NTVC6BB</string>
    </array>
    <key>TeamName</key>
    <string>Apple Inc. - DTS VPN</string>
    <key>TimeToLive</key>
    <integer>365</integer>
    <key>UUID</key>
    <string>9237134a-dfad-4e70-b417-17a64ee86378</string>
    <key>Version</key>
    <integer>1</integer>
</dict>
</plist>
$ 
$ security cms -D -i QNEDNSProxy.app/PlugIns/Provider.appex/embedded.mobileprovision 
…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>AppIDName</key>
    <string>QNE iOS DNSProxy Provider</string>
    <key>ApplicationIdentifierPrefix</key>
    <array>
    <string>VR9NTVC6BB</string>
    </array>
    <key>CreationDate</key>
    <date>2017-07-19T11:01:24Z</date>
    <key>Platform</key>
    <array>
        <string>iOS</string>
    </array>
    <key>DeveloperCertificates</key>
    <array>
        …
    </array>
    <key>Entitlements</key>
    <dict>
        <key>com.apple.developer.networking.networkextension</key>
        <array> 
            <string>app-proxy-provider</string> 
            <string>content-filter-provider</string> 
            <string>packet-tunnel-provider</string>
            <string>dns-proxy</string>
        </array>
        <key>keychain-access-groups</key>
        <array>
            <string>VR9NTVC6BB.*</string>       
        </array>
        <key>get-task-allow</key>
        <true/>
        <key>application-identifier</key>
        <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
        <key>com.apple.security.application-groups</key>
        <array>
            <string>group.com.example.apple-samplecode.QNE-iOS</string>
        </array>
        <key>com.apple.developer.team-identifier</key>
        <string>VR9NTVC6BB</string>
    </dict>
    <key>ExpirationDate</key>
    <date>2018-07-19T11:01:24Z</date>
    <key>Name</key>
    <string>QNE iOS DNSProxy Provider</string>
    <key>ProvisionedDevices</key>
    <array>
        …
    </array>
    <key>TeamIdentifier</key>
    <array>
        <string>VR9NTVC6BB</string>
    </array>
    <key>TeamName</key>
    <string>Apple Inc. - DTS VPN</string>
    <key>TimeToLive</key>
    <integer>365</integer>
    <key>UUID</key>
    <string>c3db3b50-8db4-4cc6-94b4-84f53da9fea4</string>
    <key>Version</key>
    <integer>1</integer>
</dict>
</plist>

Same here.


Maybe this API isn't functional yet?

Since there is no response on the forum here, I opened up radar 33322220 with sample code they can download.

Accepted Answer

I only had a short amount of time to play with this today but I did manage to get the provider loading. I’m going to address some specific points in your original post and then describe what I did.

You wrote:

I'm able to loadFromPreferences() …

Did you actually call

saveToPreferences(completionHandler:)
? I don’t see that anywhere in the snippets you posted.

I think my entitlements look good:

You should dump the entitlements of the

.appex
inside your
.app
, rather than the one at the top level of your build results folder. That ensures that you’re dumping the entitlements that are actually being looked at by iOS.

You should also dump your provisioning profiles to ensure that they whitelist the entitlements you use (specifically

com.apple.developer.networking.networkextension
).

One thing that is confusing is that in NEDNSProxyManager.h,

enabled
is the property but I can't set
enabled
in Xcode.

Right. That’s a Swift thing. In Objective-C you have the

isEnabled
getter paired to the
enabled
setter, but Swift exposes both as
isEnabled
so as to conform to standard Swift style.

NEDNS Proxy doesn't seem to be available for macos, just iOS.

Correct.

So, I sat down to play with this API today and managed to get it to the point where the provider actually loads and

startProxy(options:completionHandler:)
is called. My provider looks very much like yours. The only change I made was to delete extraneous stuff.
import NetworkExtension

class DNSProxyProvider: NEDNSProxyProvider {

    override init() {
        NSLog("QNEDNSProxy.Provider: init")
        super.init()
        // +++ might want to set up KVO on `systemDNSSettings`
    }

    override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
        NSLog("QNEDNSProxy.Provider: start")
        completionHandler(nil)
    }

    override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
        NSLog("QNEDNSProxy.Provider: stop")
        completionHandler()
    }

    override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
        NSLog("QNEDNSProxy.Provider: new flow (denied)")
        return false
    }
}

Note that all my log messages include QNEDNSProxy, which helps when it comes to debugging (more on this below).

My loading code is also very similar to yours:

private func enable() {
    self.update {
        self.manager.localizedDescription = "QNEDNSProxy Test"
        let proto = NEDNSProxyProviderProtocol()
        // proto.providerConfiguration = +++
        proto.providerBundleIdentifier = "com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider"
        self.manager.providerProtocol = proto
        self.manager.isEnabled = true
    }
}

private func disable() {
    self.update {
        self.manager.isEnabled = false
    }
}

private func update(_ body: @escaping () -> Void) {
    self.manager.loadFromPreferences { (error) in
        guard error == nil else {
            NSLog("QNEDNSProxy.App: load error")
            return
        }
        body()
        self.manager.saveToPreferences { (error) in
            guard error == nil else {
                NSLog("QNEDNSProxy.App: save error")
                return
            }
            NSLog("QNEDNSProxy.App: saved")
        }
    }
}

Note that I’m calling

saveToPreferences(completionHandler:)
, which is required per my comments above.

Beyond that it was just a question getting the provisioning and entitlements correct. I’ve pasted in dumps of those at the end of this email.

IMPORTANT The app group is not needed for this minimal example. It was inherited from the Network Extension template, which includes it because it’s probably going to be useful in the long term.

Finally, some debugging hints. I wired up the

enable()
and
disable()
methods to buttons in my test app. I then ran the Console utility on my Mac and selected my iPhone on the left. I then entered QNEDNSProxy into the search field so that I see all messages related to be app and its provider. At that point I could see the system make progress as it tried to load my provider. When things started to go wrong — for example, when I saw messages about the state changing from ‘starting’ to ‘stopping’ — I removed the QNEDNSProxy search term and started looking at all the messages that were likely to be related to this task. I eventually found a log message from
pkd
(the daemon responsible for PlugInKit, the infrastructure used by app extensions) which indicated that I had set
providerBundleIdentifier
incorrectly.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
$ codesign -d --entitlements :- QNEDNSProxy.app/PlugIns/Provider.appex
Executable=/Users/quinn/DTS Work iOS/Samples and Tests/QNE/QNEDNSProxy-GIT/build/Debug-iphoneos/QNEDNSProxy.app/PlugIns/Provider.appex/Provider
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
    <key>com.apple.developer.networking.networkextension</key>
    <array>
        <string>dns-proxy</string>
    </array>
    <key>com.apple.developer.team-identifier</key>
    <string>VR9NTVC6BB</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.apple-samplecode.QNE-iOS</string>
    </array>
    <key>get-task-allow</key>
    <true/>
</dict>
</plist>
$ 
$ codesign -d --entitlements :- QNEDNSProxy.app/PlugIns/Provider.appex
Executable=/Users/quinn/DTS Work iOS/Samples and Tests/QNE/QNEDNSProxy-GIT/build/Debug-iphoneos/QNEDNSProxy.app/PlugIns/Provider.appex/Provider
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
    <key>com.apple.developer.networking.networkextension</key>
    <array>
        <string>dns-proxy</string>
    </array>
    <key>com.apple.developer.team-identifier</key>
    <string>VR9NTVC6BB</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.apple-samplecode.QNE-iOS</string>
    </array>
    <key>get-task-allow</key>
    <true/>
</dict>
</plist>
$
$ security cms -D -i QNEDNSProxy.app/embedded.mobileprovision 
…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>AppIDName</key>
    <string>QNE iOS DNSProxy</string>
    <key>ApplicationIdentifierPrefix</key>
    <array>
    <string>VR9NTVC6BB</string>
    </array>
    <key>CreationDate</key>
    <date>2017-07-19T11:01:01Z</date>
    <key>Platform</key>
    <array>
        <string>iOS</string>
    </array>
    <key>DeveloperCertificates</key>
    <array>
        …
    </array>
    <key>Entitlements</key>
    <dict>
        <key>com.apple.developer.networking.networkextension</key>
        <array> 
            <string>app-proxy-provider</string> 
            <string>content-filter-provider</string> 
            <string>packet-tunnel-provider</string>
            <string>dns-proxy</string>
        </array>
        <key>keychain-access-groups</key>
        <array>
            <string>VR9NTVC6BB.*</string>       
        </array>
        <key>get-task-allow</key>
        <true/>
        <key>application-identifier</key>
        <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy</string>
        <key>com.apple.security.application-groups</key>
        <array>
            <string>group.com.example.apple-samplecode.QNE-iOS</string>
        </array>
        <key>com.apple.developer.team-identifier</key>
        <string>VR9NTVC6BB</string>
    </dict>
    <key>ExpirationDate</key>
    <date>2018-07-19T11:01:01Z</date>
    <key>Name</key>
    <string>QNE iOS DNSProxy</string>
    <key>ProvisionedDevices</key>
    <array>
        …
    </array>
    <key>TeamIdentifier</key>
    <array>
        <string>VR9NTVC6BB</string>
    </array>
    <key>TeamName</key>
    <string>Apple Inc. - DTS VPN</string>
    <key>TimeToLive</key>
    <integer>365</integer>
    <key>UUID</key>
    <string>9237134a-dfad-4e70-b417-17a64ee86378</string>
    <key>Version</key>
    <integer>1</integer>
</dict>
</plist>
$ 
$ security cms -D -i QNEDNSProxy.app/PlugIns/Provider.appex/embedded.mobileprovision 
…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>AppIDName</key>
    <string>QNE iOS DNSProxy Provider</string>
    <key>ApplicationIdentifierPrefix</key>
    <array>
    <string>VR9NTVC6BB</string>
    </array>
    <key>CreationDate</key>
    <date>2017-07-19T11:01:24Z</date>
    <key>Platform</key>
    <array>
        <string>iOS</string>
    </array>
    <key>DeveloperCertificates</key>
    <array>
        …
    </array>
    <key>Entitlements</key>
    <dict>
        <key>com.apple.developer.networking.networkextension</key>
        <array> 
            <string>app-proxy-provider</string> 
            <string>content-filter-provider</string> 
            <string>packet-tunnel-provider</string>
            <string>dns-proxy</string>
        </array>
        <key>keychain-access-groups</key>
        <array>
            <string>VR9NTVC6BB.*</string>       
        </array>
        <key>get-task-allow</key>
        <true/>
        <key>application-identifier</key>
        <string>VR9NTVC6BB.com.example.apple-samplecode.QNE-iOS.DNSProxy.Provider</string>
        <key>com.apple.security.application-groups</key>
        <array>
            <string>group.com.example.apple-samplecode.QNE-iOS</string>
        </array>
        <key>com.apple.developer.team-identifier</key>
        <string>VR9NTVC6BB</string>
    </dict>
    <key>ExpirationDate</key>
    <date>2018-07-19T11:01:24Z</date>
    <key>Name</key>
    <string>QNE iOS DNSProxy Provider</string>
    <key>ProvisionedDevices</key>
    <array>
        …
    </array>
    <key>TeamIdentifier</key>
    <array>
        <string>VR9NTVC6BB</string>
    </array>
    <key>TeamName</key>
    <string>Apple Inc. - DTS VPN</string>
    <key>TimeToLive</key>
    <integer>365</integer>
    <key>UUID</key>
    <string>c3db3b50-8db4-4cc6-94b4-84f53da9fea4</string>
    <key>Version</key>
    <integer>1</integer>
</dict>
</plist>

Thanks! Adding the saveToPreferences() did the trick. It pops up a scary VPN message though. Can that be made any less scary for DNS?

Can that be made any less scary for DNS?

You should file a bug report with you suggestions. Please post your bug number, just for the record.

Speaking personally, a scary alert seems pretty appropriate here given how central the DNS is to network security.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Two questions :


1. How/where do I mention custom DNS Server's IP?

2. I implemented the same process. Created a new Network Extension named DNSProxySample. Added entitlements and connected everything as mentioned by your answer. Though saveToPreferences() is called and the preferences are saved as well. But startProxy() is never called. Can you help me finding what is not working here?


Thanks!

1. How/where do I mention custom DNS Server's IP?

I don’t understand this question. The point of the DNS proxy is that your provider receives DNS queries and can resolve them in arbitrary ways; there’s no need to give the system custom DNS service IP addresses because you are in control of the actual networking (if any) that’s being done.

2. I implemented the same process. Created a new Network Extension named DNSProxySample. Added entitlements and connected everything as mentioned by your answer. Though saveToPreferences() is called and the preferences are saved as well. But startProxy() is never called. Can you help me finding what is not working here?

The number one reason for problems like this is entitlements. Make sure you check the entitlements of the built binaries and the entitlements in the corresponding provisioning profiles as I’ve shown above. Do not rely on what you see in the

.entitlements
file; that’s an input to the code signing process, not what the system actually checks.

Beyond that, I don’t have any obvious suggestions as to what’s gone wrong. I recommend you look in the system log to see if there’s some obvious red flag there.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I wanted to use this DNS Proxy network extension to provide privacy to users by sending DNS queries upstream over TLS. This would prevent local providers from monitoring or collecting DNS traffic from it's users and use QNAME minimization to limit the queries. There is a big push within the IETF to transition DNS to use TLS and increase privacy for everyone.


However, this message in the iOS console says it's only for supervised devices. This makes it almost useless because most people will never use a supervised device and they can't just install it from the App Store. I opened a radar to please reconsider this restriction: 34843801


Oct 5 17:29:26 iPhone nehelper(NetworkExtension)[99] : -[NEHelperConfigurationManager:562 Warning: allowing creation/modification of a DNS proxy configuration on non-supervised device because the requesting app (DNS-TLS) is a development version. This will not be allowed for the production version of DNS-TLS

However, this message in the iOS console says it's only for supervised devices.

Hmmm, that’s not what I was expected. I’m going to check on this and get back to you.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Tom Pusateri wrote:

However, this message in the iOS console says it's only for supervised devices.

I wrote:

Hmmm, that’s not what I was expected.

Someone else asked about this on a different thread and I’ve posted the details over there.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Eskimo,

Thanks for your responses on this topic.

Regarding the custom DNS Server IP - wouldn't it be possible to direct the DNS resolution to external DNS Server and not do it in directly inside the proxy provider?

NEDNSProxyProviderProtocol that is used to configure the NEDNSProxyManager has a property that allows you to set the proxy settings like http/https server. Do you know if it affects the DNS proxy in any way?

wouldn't it be possible to direct the DNS resolution to external DNS Server and not do it in directly inside the proxy provider?

Let me see if I understand you properly. You are trying to avoid writing actual DNS networking code, but instead want some sort of shortcut mechanism whereby your DNS proxy provider can simply set a custom DNS server IP address that the system will then honour. Is that right?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

@eskimo Actually this was my requirement as well. With the help of DNS Proxy API, Is it possible to set a custom DNS server IP which can be honored by the entire device?

With the help of DNS Proxy API, Is it possible to set a custom DNS server IP which can be honored by the entire device?

No. A DNS proxy provider is intended to provide a custom DNS transport. The system forwards all DNS queries to the provider and the provider is then responsible for responding to them. Typically it does this by forwarding the queries down a tunnel to some existing DNS infrastructure, but there’s no specific requirement that things work that way. It does not, however, provide a simple way to override system DNS settings.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

@eskimo Hi, I am sorry to bother you. I finish my app and its function is also normal accroding to you reply. But when i publish it by Testflight, there are some thing wrong. When I open proxy, I don not see the alert of VPN Authorization and get error -- permission dinied. I want to know why and how to resolve it. I am looking forward to your reply, thank u

DNS Proxy Network Extension startProxy
 
 
Q