`NEProxySettings.matchDomains` / `exceptionList` not working as expected in `NEPacketTunnelProvider` (domain-scoped proxy not applied, and exceptions not bypassed)

I’m working on an iOS Network Extension where a NEPacketTunnelProviderconfigures a local HTTP/HTTPS proxy usingNEPacketTunnelNetworkSettings.proxySettings.

Per NEProxySettings.exceptionList docs:

If the destination host name of an HTTP connection matches one of these patterns then the proxy settings will not be used for the connection.

However, I’m seeing two distinct issues:

  • Issue A (exception bypass not working): HTTPS traffic to a host that matches exceptionList still reaches the proxy.
  • Issue B (domain-scoped proxy not applied): When matchDomains is set to match a specific domain (example: ["googlevideo.com"]), I still observe its traffic in some apps is not proxied. If I remove the domain from matchDomains, the same traffic is proxied.

Environment

  • OS: iOS (reproduced with 26.4 and other versions)
  • Devices: Reproduced with several iPhones (likely iPads as well)
  • Xcode: 26.3
  • Extension: NEPacketTunnelProvider

Minimal Repro (code)

This is the minimal configuration. Toggle between CONFIG A / CONFIG B to reproduce each issue.

import NetworkExtension

final class PacketTunnelProvider: NEPacketTunnelProvider {
    override func startTunnel(
        options: [String : NSObject]? = nil,
        completionHandler: @escaping (Error?) -> Void
    ) {
        let proxyPort = 12345 // proxy listening port

        let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8")

        let proxySettings = NEProxySettings()
        proxySettings.httpEnabled = true
        proxySettings.httpsEnabled = true
        proxySettings.httpServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address
        proxySettings.httpsServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address

        // CONFIG A: proxy all domains, but exclude some domains
        // proxySettings.matchDomains can be set to match all domains
        // proxySettings.exceptionList = ["*.cdninstagram.com", "cdninstagram.com"]

        // CONFIG B: proxy only a specific domain
        // proxySettings.matchDomains = ["googlevideo.com"]

        settings.proxySettings = proxySettings

        setTunnelNetworkSettings(settings) { error in
            completionHandler(error)
        }
    }
}

Repro steps

Issue A (exceptionList bypass not working)

  1. Enable the VPN configuration and start the tunnel with CONFIG A (exceptionList = ["*.cdninstagram.com", "cdninstagram.com"]).
  2. Open the Instagram app to trigger HTTPS connections to *.cdninstagram.com
  3. Inspect proxy logs: cdninstagram.com traffic is still received by the proxy.

Safari comparison:

  • If I access URLs that trigger the same *.cdninstagram.com hosts from Safari, it can behave as expected.
  • When the traffic is triggered from the Instagram app, the excluded host still reaches the proxy as CONNECT, which is unexpected.

Issue B (matchDomains not applied for YouTube traffic)

  1. Start the tunnel with CONFIG B (matchDomains = ["googlevideo.com"]).
  2. Open the YouTube app and start playing a video (traffic typically targets *.googlevideo.com).
  3. Inspect proxy logs: googlevideo.com traffic is not received by the proxy.
  4. Remove the host from matchDomains and observe that googlevideo.com traffic is received by the proxy.

Safari comparison:

  • If I access a googlevideo.com host from Safari while matchDomains = ["googlevideo.com"], it behaves as expected (proxied).
  • In contrast, the YouTube app’s googlevideo.com traffic is not proxied unless I match all domains.

Expected

Issue A

Connections to *.cdninstagram.com in the Instagram app should not use the proxy and should not reach the local proxy server.

Issue B

With matchDomains = ["googlevideo.com"], traffic to *.googlevideo.com (YouTube video traffic) should be proxied and therefore reach the local proxy.

Actual

Issue A

The local proxy still receives the request as:

CONNECT scontent-mad1-1.cdninstagram.com:443 HTTP/1.1

So the bypass does not happen.

Issue B

With matchDomains = ["googlevideo.com"], I still observe googlevideo.com traffic in the YouTube app that is not delivered to the proxy. When all traffic is proxied, the same traffic is delivered to the proxy.

Answered by DTS Engineer in 882748022

Are you actually building a VPN product?

I suspect that’s not the case, given that you’re using a placeholder for tunnelRemoteAddress. And if that’s true then… well… there are limits to how much I can help you here.

My experience is that developers often try to use a packet tunnel provider for things that are not VPN. DTS doesn’t support those efforts because they tend to be very brittle. One of my erstwhile colleagues even wrote a technote about this, namely, TN3120 Expected use cases for Network Extension packet tunnel providers.

If you’re trying to use a packet tunnel provider for something that isn’t VPN, I recommend that you watch WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension, where one of the engineers from the NE team explains the various alternatives that are available to you, including the new URL filter provider.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Are you actually building a VPN product?

I suspect that’s not the case, given that you’re using a placeholder for tunnelRemoteAddress. And if that’s true then… well… there are limits to how much I can help you here.

My experience is that developers often try to use a packet tunnel provider for things that are not VPN. DTS doesn’t support those efforts because they tend to be very brittle. One of my erstwhile colleagues even wrote a technote about this, namely, TN3120 Expected use cases for Network Extension packet tunnel providers.

If you’re trying to use a packet tunnel provider for something that isn’t VPN, I recommend that you watch WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension, where one of the engineers from the NE team explains the various alternatives that are available to you, including the new URL filter provider.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

`NEProxySettings.matchDomains` / `exceptionList` not working as expected in `NEPacketTunnelProvider` (domain-scoped proxy not applied, and exceptions not bypassed)
 
 
Q