Hi,
I've encountered a strange behavior in the DNS Proxy Provider extension. Our app implements both DNS Proxy Provider and Content Filter Providers extensions, configured via MDM.
When the app is uninstalled, the behavior of the providers differs:
- For Content Filter Providers (both Filter Control and Filter Data Providers), the providers stop as expected with the stop reason:
/** @const NEProviderStopReasonProviderDisabled The provider was disabled. */
case providerDisabled = 5
- However, for the DNS Proxy Provider, the provider remains in the "Running" state, even though there is no app available to match the provider's bundle ID in the uploaded configuration profile.
When the app is reinstalled:
- The Content Filter Providers start as expected.
- The DNS Proxy Provider stops with the stop reason:
/** @const NEProviderStopReasonAppUpdate The NEProvider is being updated */
@available(iOS 13.0, *)
case appUpdate = 16
At this point, the DNS Proxy Provider remains in an 'Invalid' state. Reinstalling the app a second time seems to resolve the issue, with both the DNS Proxy Provider and Content Filter Providers starting as expected.
This issue seems to occur only if some time has passed after the DNS Proxy Provider entered the 'Running' state. It appears as though the system retains a stale configuration for the DNS Proxy Provider, even after the app has been removed.
Steps to reproduce:
- Install the app and configure both DNS Proxy Provider and Content Filter Providers using MDM.
- Uninstall the app.
- Content Filter Providers are stopped as expected (NEProviderStopReason.providerDisabled = 5).
- DNS Proxy Provider remains in the 'Running' state.
- Reinstall the app.
- Content Filter Providers start as expected.
- DNS Proxy Provider stops with NEProviderStopReason.appUpdate (16) and remains 'Invalid'.
- Reinstall the app again.
- DNS Proxy Provider now starts as expected.
This behavior raises concerns about how the system manages the lifecycle of DNS Proxy Provider, because DNS Proxy Provider is matched with provider bundle id in .mobileconfig
file.
Has anyone else experienced this issue? Any suggestions on how to address or debug this behavior would be highly appreciated.
Thank you!
Here’s an example of multiple flows observed with the same sourceAppSigningIdentifier and bytes, but different local ports:
That’s not flow duplication. When talking about UDP, flows are identifier by the tuple local IP / local port / remote IP / remote port. If the flows have different local ports, they are different flows.
I’m not sure what’s happening with Set
in this case. Honestly, I could research that but I think that are bigger fish to fry here.
all DNS proxy functionality is now contained within a single class.
That’s impressive, because creating a DNS proxy is a complex task. However, looking at the code it’s clear that you’re not handling your flows correctly.
The issue is that you read one set of requests from the flow, resolves those, write the responses, and then close the flow. That’s not how a DNS proxy is supposed to work. Rather, it should stream queries in from the flow, resolve them, and then stream replies back.
IMPORTANT You don’t have to reply in order because the DNS client is expected to match replies to queries via the message’s Transaction ID field.
That explains why things are working for your DNS test tool (case 1 above) but failing for the real DNS client (case 2). It also explains why you’re seeing so many flows. My experience with DNS proxies is that they see very few flows. You get a flow from mDNSResponder
and all DNS traffic runs through that until you either a) run an app or tool that doesn’t using the built-in resolver, like dig
, or b) something causes that flow to stop, like a network reconfiguration. You might see a few extra flows here and there, but nothing like the number you’re seeing.
Now, mDNSResponder
should be able to handle the flow being closed and recover. It’s possible that iOS 18.4 has introduced a bug that’s causing that to fail. Regardless, the current behaviour of your proxy is incorrect and you should fix that. That might help with this problem, but it’s the right thing to do anyway.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"