|January 27th, 2014|
A large number of the world’s wireless carriers enable internet tethering by default for no extra charge when using an iPhone (because data is just data after all). In the United States, no major carrier has had the good sense to do it even with data caps and throttling. Any way you look at it, paying for tethering is a bad deal. So what then are your options when you want to use your phone’s internet connection on your laptop? You can always jailbreak and enable iOS’s built-in tethering (marketed as “Personal Hotspot“) using a tweaked carrier profile or install a stanadlone tethering app. However, jailbreaking has known risks associated with it and some US carriers have stated that they will cut your service if they detect tethering without the requisite contract on their end (exactly what detection methods they employ and how much work they have invested in enforcement remains unclear). What then are we left with? Proxying.
Proxying != Tethering
Proxying is different from tethering in significant ways. Instead of routing traffic on the network level, a proxy app receives requests from a client (the laptop) through a known proxying protocol to make network requests as itself on behalf of the client (essentially performing routing on the application level). As far as the rest of the internet is concerned, there is just some app on your phone using the internet connection. The proxying app on the phone is simply making all the requests for itself. It just so happens that when it receives the responses, it passes them back across the proxying protocol to the laptop.
OS X has support for proxying basic services like HTTP (80) and HTTPS (443) and a few others. So unlike tethering, you do not have the full range of ports at your command but you can still get a lot done over ports 80 and 443 these days. But the key difference from tethering to us is that the functionality to proxy can be performed entirely within a fully-sandboxed iOS app, running on an un-jailbroken iOS device.
App Store Intrigue
Proxying apps have appeared in Apple’s App Store from time to time. Sometimes the functionality is hidden within apps as easter eggs that need activation and sometimes it is just in plain sight. In every case, Apple always mysteriously pulls them without explanation (proxying does not violate any of the App Store Guidelines). It seems that the best way to get a proxying app on your iOS device is to simply build it yourself with a developer certificate. If you (or a friend) are a registered Apple developer with an iOS signing certificate, then you can download the source code to any number of proxying apps for iOS, build it yourself and load it on to your device directly. Even after building and getting it to run on your device, there are still complicated setup steps required (on both iOS and OS X) that are well documented but will not be covered here.
The most popular proxying app on iOS for the last couple of years has been iProxy. iProxy is open-source but it hasn’t been worked on for a few years. As time marches on, bit-rot emerges and future compatibility starts to falter. When I recently upgraded to an iPhone 5S (gold of course) I found that iProxy no longer worked. So I dug into the source and fired up the debugger to see what happened.
Well There’s Your Problem!
After a fair amount of tests and debugging, it seemed that the main problem with iProxy on iOS 7 related to obtaining the IP address of the DNS server for the cell connection. Without that, it appears you can still create network requests to specific IPs, but you can’t resolve any domain names which severely limits what you can do on the internet.
Previously, polipo (the web proxying project that iProxy is based on) tried to obtain this IP by reading
/etc/resolv.conf from the filesystem and parsing it’s contents. On iOS 7 it appears like this file either no longer exists or is no longer accessible from 3rd-party apps. Fortunately, this problem is easily fixed. libresolv contains routines that we can use to obtain the IP of the DNS server and so we can just use those. After integrating these new routines and making a couple of other small housekeeping changes, it looked like the broken functionality was now fixed on iOS 7.
Unfortunately, things still didn’t work on my new Mavericks laptop. What was curious though was that when I proxied my old Snow Leopard laptop, everything worked! After a lot of thrashing, some network capture sessions using Instruments.app and some dumb luck, I found the solution. You need to enter the IP of the iOS device running iProxy (as noted in the Wi-Fi Settings) into the “DNS Servers” list of the OS X Network Preferences Pane for the Wi-Fi connection. At last, it finally worked as intended! Update: It appears like there is some issue at play on the Mac side of things that may cause it to not work quite yet at this point. I have found that having the Mac disconnect itself from it’s own ad-hoc wireless network and then reconnecting it can help.
So after getting my hands dirty for a bit, my new hardware setup now is complete with a proxying solution that lets me fix things in a pinch when I am out and about or keep my sanity on long family car trips. I have forked the original iProxy project on github and committed my changes for anyone else to play around with. iProxy is in great need of a complete overhaul, but in the meantime my little tweaks will keep it on life support as iOS moves forward.