Does SCNetworkReachability respect HTTP proxy settings? - ios

I'm afraid the answer to this is No, but I'm hoping someone can provide a definitive answer as it is not documented in the current iOS SDK documentation.
We're seeing a case where NSURLConnection is able to connect to https://mysite.com via an HTTP proxy but, because of the way the local DNS is setup in this case, DNS lookups for mysite.com will fail. In this case, it appears that SCNetworkReachability is trying to perform a DNS lookup for mysite.com and failing. Meanwhile, NSURLConnection is able to connect.
We have incorporated the Apple Reachability sample code into our app and are calling SCNetworkReachabilityCreateWithName with mysite.com.

I can't provide a definitive answer, but I can provide more empirical evidence, and some justification, that the answer is NO. I have an app that uses SCNetworkReachabilityGetFlags to check whether a particular host is reachable (e.g.: www.mysite.com). Depending on that reachability check, it then uses [NSMutableData dataWithContentsOfURL:] to download the data.
The app has always worked fine, but recently I've been doing some coding at work where network access is via the corporate HTTP proxy. When running the app in the iOS Simulator (which uses the proxy settings configured on my Mac) the reachability check fails. At first I thought that perhaps the iOS Simulator wasn't using the Mac's proxy settings, but Mobile Safari in the simulator worked fine. So I removed the reachability check in my app and the call to [NSMutableData dataWithContentsOfURL:] worked fine. This would appear to indicate that SCNetworkReachability does not respect the proxy settings.
Having thought about it, this is probably the correct behaviour if you view SCNetworkReachability as running at the TCP/IP level, not at the HTTP level, in the same way that ping google.com on a Mac/PC behind a corporate firewall doesn't work either. The HTTP proxy (as the name implies) is for the HTTP protocol, not the whole TCP/IP stack.
Having read the answers to this question on Reachability I'm inclined to bin my reachability check altogether. Even though it's only been a problem in the simulator until now, it could be problematic in other situations (e.g. public WiFi hotspot that requires authentication).

Related

Proxy websocket connections in iOS NEPacketTunnelProvider using NEKit

When I use Charles Proxy for iOS and play some games, I recognize that they etablish connections with the protocol prefix "socket://" followed by an IP address (instead of a hostname, which is always present for other HTTP(s) connections). I'd assume that those are websockets.
Currently, I'm trying to implement a tool to track rudimentary network activity. To archive that, I'm using the NEKit (https://zhuhaow.me/NEKit/) in combination with the NEPacketTunnelProvider extension for iOS. Using that, I was able to set up a local HTTP Proxy server and setup the network interface to redirect every HTTP(s) request over that local proxy. Through an observer, I was able to see all the requested hostnames.
Now I found out, that some games (those which are using websockets) are not working properly with my solution. Regarding to this discussion https://news.ycombinator.com/item?id=16694670 it seems like proxying the HTTP(s) data flow doesn't enable me to handle websocket connections:
Yes, but the problem with Charles (well, iOS related at least) is that iOS websockets don't go through the HTTP Proxy configured. They're just considered a raw socket. Thus, even on desktop Charles, it's a nogo.
Due to that, some apps don't even work when my tracker is enabled, since they can't etablish a connection to their servers.
Is there the possibility to archive something similar for the websocket connections since the combination of GCDHTTPProxyServer (NEKit) and NEProxySettings (NetworkExtension) is only working for HTTP(s)? How can I track and (even better) proxy websocket connections?

iOS app sandbox for accepting connections on TCP sockets

I'm making use of the library GCDWebServer(https://github.com/swisspol/GCDWebServer) in a project of mine, that requires me to accept connections originating only from my application's process, for security reasons. I was hoping this is something that the iOS app sandbox would provide out of the box, but that doesn't appear to be the case. The sandbox appears to be enforced for UNIX domain sockets(AF_UNIX), by means of file-system permissions. But for TCP/IP sockets(AF_INET), used by GCDWebServer, there appears to be no sandboxing in place.
I was able to write two sample applications - a client and a server(signed with different developer certificates) and could have them communicate with each other, without any issues.
I was wondering if there was some way of enforcing the same on iOS, essentially spin up a HTTP server on a TCP socket but only accept connections from the same process. I can't make use of UNIX domain sockets, because the client which is going to request the content from the HTTP server is an AVPlayer and it wouldn't know how to connect to my application's UNIX domain socket.
I'm about 99% certain that what you're asking for is impossible. I don't even think it is possible in OS X without writing a network kernel extension (and even then, it would be challenging).
By the time a network request reaches another process, it has passed through the networking stack and has lost any notion of what process originated the connection (unless this has improved fairly recently).
Realistically, the closest you can get is binding to a random port on the localhost interface and tearing it down as soon as your app gets put into the background.
Pedantically, if you managed to somehow convince Apple that you planned to build a VPN, it is theoretically possible to abuse the VPN API in such a way that would let you provide a private network that worked only within your app. It would not, however, ever be allowed in the app store.
But why would you ever want to do this? AVPlayer is more than capable of playing from a file URL.
There are many ways you could do that: you can inspect the incoming request in GCDWebServer and decide if you want to respond to it or return an error.
You could add a secret header other apps wouldn't know about, sign the entire request with a secret key, etc...

How to select specific network interface for NSURLSession connections?

I’m not talking about Reachability.
What I’m talking about is figuring out how to create a network connection from an iOS device across the cellular interface.
Why? Because I have conditions where the device connects to a WiFi access point so it chooses WiFi… but that access point is not internet connected and goes nowhere. I have data which I must make every effort to deliver and it some cases it’s getting lost in the WiFi gateway to purgatory. In both cases of using Reachability and relying on MPTCP, Apple has already given priority to WiFi in the stack.
I know NSURLSessionConfiguration can set allowsCellularAccess to allow cellular access — I’m looking to require cellular for the routing.
Even at the CFNetwork level I’m looking at kCFStreamPropertyConnectionIsCellular for status, kCFStreamPropertyNoCellular to disable cellular.
I can’t find anyway to give preference to the cellular radio. I realize Apple has gone to great lengths to prefer WiFi and I’m going against that — which is why I’m having such difficulty finding an answer to this.
I'd like to keep this up in the Cocoa level, but not opposed to going into Foundation or deeper levels. I would like to avoid trying to parse an interface table (if it's even accessible) to figure out which is the cellular interface.
Has anyone successfully created a network connection across the cellular link despite WiFi appearing to be present?
Is some configuration of Multipath TCP the answer here?
To bind to a particular interface, as far as I'm aware, you'd have to drop all the way down to the raw socket level, and there's no way to provide a custom socket for NSURLSession purposes, so you'd basically be rewriting it from scratch. You should file a bug asking for support for binding an NSURLSession to a source IP.
The behavior you're experiencing is a known problem with iOS and disconnected networks. iOS 9 and later do a better job, but even then, they can be highly problematic; the devices sometimes refuse to talk to the Wi-Fi network, and sometimes refuse to talk to the cellular network. Specifically, it seems to fail spectacularly if either signal is weak. Just this morning, I actually had to force my iPhone (iOS 10) to talk to a disconnected Wi-Fi network by putting it in Airplane mode and enabling only Wi-Fi.
I'm told that you can fix this by configuring the network's DHCP server to not provide a router advertisement; that said, every time I've tried that, the iOS device would just keep asking for an offer repeatedly. Maybe that bug got fixed at some point. If so, it might be worth a shot, but don't expect it to work in older versions of iOS.
Failing that, assuming you don't need to support web browsers in iOS 3 and earlier, you might try eliminating the DHCP server on that Wi-Fi network entirely, and just rely on DNS service discovery with zero-conf IPs. That way, the device won't see a router, and it won't try to send data out that interface except to those link-local IPs.
If that isn't possible for some reason, ordinarily I would suggest using a customized copy of libcurl, except that I doubt this will work in your case, because POSIX networking doesn't wake the cellular hardware.
In iOS 12 and later you can use the Network Framework. Sample code is here.

Bulletproof HTTP Monitor for iOS

I'm using Charles Proxy and Wireshark to monitor http(s) traffic from various iOS apps I'm using on my iPhone. These apps require me to set the HTTP Proxy under the iOS Wifi settings (let's call these the Proxy Settings).
My business needs to see ALL URL's that are being called from my phone. From all apps. All URL's, not some of them.
Now Charles and Wireshark both work fine and I can see a ton of traffic coming from my phone.
However, I can't help but wonder whether I might be missing some HTTP calls. Maybe calls that don't use the Cocoa Core Foundation libraries as the basis for their networking.
For instance, I could write my own HTTP library out of TCP/IP and these would bypass the Proxy Settings.
So my question is: what is the likelihood that some apps are using custom-rolled HTTP libraries and side-stepping my Proxy Settings. Or worse, they're using raw TCP/IP to communicate with a server. I know it's possible, but do any APIs work this way? Does anyone do it?
I found the answer: Use mitmproxy in transparent mode. proxy is not used. harder to setup because it needs work on the router, but it reliably captures every packet on port 80 and 443 regardless of proxy settings.
Assuming that you are able to keep your device tethered, then you may be able to use the pcap service to monitor all traffic. According to the following paper (2014) the pcap service is running on every iOS device:
"Identifying back doors, attack points, and surveillance mechanisms in iOS devices"
You should be able to connect to it via usbmuxd. I'm not sure whether there is a pre-rolled client for the pcap service. There is a list of services supported by libimobiledevice here. Pcap is not on that list.
Alternatively, you can use wireshark to capture all traffic on your wifi network.

seeing http requests that ios app makes

I'd like to see the request / responses that an iphone app makes.
I mostly work on web apps, and I can use firebug / fiddler to see them. But how can I see incoming/outgoing traffic of an iOS app, if im running it on my wireless?
The Charles Web Proxy (and I believe Fiddler as well) allow connections from external hosts, when configured properly. In Charles, you will need to make sure your iPhone is added to the Access Control List in Proxy -> Access Control Settings.
After that, you can simply set your iPhone's proxy to your computer's Charles or Fiddler instance. In my case, my local desktop is at 192.168.10.1, thus my iPhone's proxy is set to:
192.168.10.1:8888
One problem, however, may be if you want to decrypt SSL traffic. It may be difficult to get the iPhone to add Fiddler or Charles' certificate to the keychain.
You could share your mac wireless to the iphone
And then use some tool, i personally use http://www.charlesproxy.com/ for these kind of issues
You could pick a tool from
https://superuser.com/questions/99870/mac-wireshark-alternatives

Resources