Search code examples
objective-ciosproxyasyncsocket

Setting Proxy On iOS CFStreams Not Working


I have setup a squid http proxy on my Mac and I have setup my Mac to share its wireless connection. In the wifi connection information on my phone I have setup my HTTP Proxy Settings:

Server: 10.0.2.1
Port:   3128
Authentication: off

In my iOS application I have two ways of accessing the network. For http requests I am using NSURLRequest and for other TCP connections I am using the AsyncSocket library.

All requests using NSURLRequest use the proxy without an issue (for SSL, the proxy acts as a HTTP CONNECT tunnel). However, I cannot seem to get the proxy to be used for the AsyncSocket connections.

I did update the AsyncSocket library to call the following whenever the CFStreams are created e.g.:

//for printing out the proxy settings
static void printEntry (const void* key, const void* value, void* context) {
    CFShow(key);
    CFShow(value);
}

- (BOOL)createStreamsFromNative:(CFSocketNativeHandle)native error:(NSError **)errPtr
{
    // Create the socket & streams.
    CFStreamCreatePairWithSocket(kCFAllocatorDefault, native, &theReadStream, &theWriteStream);
    .
    .
    .
    CFDictionaryRef proxyDict = CFNetworkCopySystemProxySettings();
    CFDictionaryApplyFunction(proxyDict, printEntry, NULL); // I see the proxy settings are correct here

    CFReadStreamSetProperty(theReadStream, kCFStreamPropertyHTTPProxy, proxyDict);
    CFWriteStreamSetProperty(theWriteStream, kCFStreamPropertyHTTPProxy, proxyDict);

    CFRelease(proxyDict);
    return YES;
}

Anything obvious I have missed here?


Solution

  • From the apple documentation:

    https://developer.apple.com/library/ios/#DOCUMENTATION/Networking/Conceptual/CFNetwork/CFStreamTasks/CFStreamTasks.html#//apple_ref/doc/uid/TP30001132-CH6-DontLinkElementID_16

    there is nothing that indicates that this shouldn't work. The documentation mentions using CFStreams, not CFHTTPStreams.

    Since I couldn't get it to work as the documentation states and I was running out of time, I implemented my own HTTP proxy code which in the end was ot too difficult. If the configuration indicated that a HTTP proxy was set, I redirected the initial connect to the proxy and initiated a HTTP request with the following headers:

    CONNECT <real host>:<real port> HTTP/1.1
    Host: <real host>
    Proxy-Connection: keep-alive
    Connection: keep-alive
    

    On receiving a complete http response with a 200 response code, I begin socket communication as if communicating directly with the server (e.g. like calling startTLS to begin SSL).