NSURLSession bypasses connectionProxyDictionary when proxy connection cannot be established

Hi Apple Engineers,

We are making an iOS app which uses NSURLSession for network communication. To provide enterprise customer the ability to monitor network traffic, we want to support proxy settings inside our app. So, we take advantage of the connectionProxyDictionary property of NSURLSessionConfiguration.

We set the kCFNetworkProxiesProxyAutoConfigURLString key, and expect requests that are scripted to be proxied to either go through the proxy or fail when proxy is not reachable. This is necessary because we don't want requests to go out without being monitored. But during development we noticed that when proxy server is not reachable, requests don't always fail with kCFErrorHTTPProxyConnectionFailure or kCFErrorHTTPSProxyConnectionFailure (CFNetworkError 306 and 310).

More specifically, the behavior we observed are as follows:

  1. PAC URL resolution timeout: Task failed with 306/310
  2. PAC URL resolution error: Task bypassed proxy and succeeded
  3. PAC file download timeout: Task failed with 306/310
  4. PAC file download error: Task bypassed proxy and succeeded
  5. PAC file parse error: Task bypassed proxy and succeeded
  6. Proxy server connection timeout: Task failed with 306/310
  7. Proxy server connection error: Task bypassed proxy and succeeded

The inconsistency of error handling behavior is confusing, is this a bug? If not, is there a way to configure NSURLSession to always yield error without bypassing the proxy when any of the above happens?

We … expect requests that are scripted to be proxied to either go through the proxy or fail when proxy is not reachable.

That’s not a valid expectation. The proxy system is designed to make requests work when they would otherwise have failed, not the other way around.

To provide enterprise customer the ability to monitor network traffic

iOS offers a number of options for enterprise customers to monitor traffic on devices they manage:

  • On device content filters

  • Per-app VPN

  • Global HTTP proxy configuration payload profile [1]

  • Probably more stuff that I’ve forgotten about (-:

Your customers should deploy one of these options.

Share and Enjoy

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

[1] Despite having “proxy” in the name, this was designed for filtering.

I've raised this issue in radar 9650785 and I believe this is an incorrect behavior of the OS.

@eskimo: I understand your point, but the PAC standard is pretty explicit in these terms, and the current way iOS is handling it is not in line with what is expected by sys admins and also works differently than essentially all other browsers and operating systems I know of.

It should be up to the PAC author to decide how the connection behaves when the proxy fails. If I want the request to work at all cost and skip the proxy when it's offline: findProxyForURL() returns "PROXY X.Y.Z; DIRECT". If I want it to fail when X.Y.Z isn't working, findProxyForURL() returns "PROXY X.Y.Z".

I don't see why iOS changed the behavior to assume "DIRECT" to be a default fallback for every connection.

@eskimo, @meaton any realistic chance this will get fixed in iOS 16? I've raised this issue through Feedback Assistant almost a year ago (24 Sep 2021) in rdar 9650785, with no success or actually any definitive answer. I still have users affected by this and complaining with no real way to provide a meaningful answer.

IMO this doesn't fall far from the VPN issue https://protonvpn.com/blog/apple-ios-vulnerability-disclosure/

any realistic chance this will get fixed change in iOS 16?

We just released iOS 16.0 RC and, AFAIK, there’s been no change in this space in that release.

Share and Enjoy

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

NSURLSession bypasses connectionProxyDictionary when proxy connection cannot be established
 
 
Q