UPDATE JUNE 2022: Whilst socket.io-client-swift has an API to enableSOCKSProxy
, it seems Starscream v4 has actually removed the built-in support for SOCKS proxying, so this option doesn't actually do anything!
So it looks like we're back to manually patching Starscream to enable SOCKS proxying.
Just to recap: we've gone from Starscream supporting SOCKS proxy but socket.io-client-swift not having an API to enable it, to now socket.io-client-swift having an API to enable SOCKS proxying, which Starscream no longer supports .
UPDATE JUNE 2019: Apparently socket.io-client-swift v15.1.0 now properly supports SOCKS proxy. I have not yet tried it, but it would mean that these manual edits to Starscream are no longer required.
The accepted answer does not seem to work with Socket.IO on iOS devices.
The latest version of Socket.IO-Client-Swift (15.0.0 at the time of writing) uses Starscream for WebSockets on iOS/OS X.
The good news is that Starscream supports SOCKS proxying however:
Socket.IO does not expose the Starscream websocket or provide any API for enabling the SOCKS proxying behaviour.
The SOCKS proxying built into Starscream uses the OS SOCKS proxy settings which are cumbersome to setup (at least for iOS).
If I get some time I might propose a PR to address this more thoroughly, but given that it requires work to both Starscream and Socket.IO-Client-Swift, this is not entirely straightforward.
The easiest way to hack around this for temporary debugging purposes (which is the use case for Charles!), is to edit the WebSocket.swift
file as part of Starscream, and replace this code:
if enableSOCKSProxy {
let proxyDict = CFNetworkCopySystemProxySettings()
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
}
with this code:
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, CFNetworkCopySystemProxySettings()!.takeRetainedValue()) as! [String: Any]
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
let ip = socksConfig["HTTPSProxy"]
let proxySocksConfig = ["SOCKSProxy": ip, "SOCKSPort": 8889, "SOCKSEnable": true] as CFDictionary // Where 8889 is the SOCKS proxy port in Charles
CFWriteStreamSetProperty(outputStream, propertyKey, proxySocksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, proxySocksConfig)
This will ensure the SOCKS proxy is enabled by default, and will route all the websockets traffic via Charles.
You then need to ensure that the HTTP proxy settings are configured in iOS (since the same IP will be used for both HTTP and SOCKS), SOCKS proxy is enabled in Charles, and that the port matches the port in the code above (by default 8889).