`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.

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