Proxying on iOS 7 | |
January 27th, 2014 | |
Spencer Nielsen |
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.
Wrap Up
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.
March 6th, 2014 at 7:43 pm
Thanks for updating the code, unfortunately I have been trying to get proxying to work for while. iProxy hasn’t been very successful (even using DNS settings). However I have found this to work quite well:
http://code.google.com/p/iphone-socks-proxy/
The best combination is for me to use Firefox plus foxyproxy to route all traffic including DNS through the proxy.
March 6th, 2014 at 10:51 pm
I have noticed that occasionally I have to kick iProxy once by going through the motions, disconnecting and then trying setup over again.
Thanks for the pointer to iphone-socks-proxy! I will check it out 🙂
March 10th, 2014 at 7:35 pm
Thank you for updating the code! I have been trying this on my new iPhone 5S which I got for my birthday last weekend, and am unfortunately not having any luck on any of the proxy apps I can find (iProxy, iphone-socks-proxy, NetShare). I can get them all on a ad-hoc network, I can ping my phone’s ip address, I can even telnet in to the port it says the proxy is on, but nothing…
I am on mavericks, 10.9.2. I did set the DNS on my laptop to the ip of my phone. But sadly nothing works. I’ve tried setting the HTTP / HTTPS proxy settings as well, tried SOCKS on the ports mentioned for HTTP, nothing. Quit my browsers, opened them again, etc etc. Nothing. Could you please help me?
I just today updated my phone to 7.1 and Xcode to 5.1. So all is up do date now. I will say I was trying these apps on my iPhone 4S which was on the 7.1 beta 5, and so now my iPhone which is on 7.1, but, when I got my phone, so for the last week, it was on 7.0.6, and nothing. So not sure if 7.1 is the issue?
March 11th, 2014 at 8:50 am
@Darren
Sometimes you need to kick it a bit to get it to work. I tried it successfully this morning with an iPhone 5S on 7.1 and a Mac on 10.9.2. Here are the specific steps it took this morning:
Created the ad-hoc wireless network on the Mac
Applied the saved “iProxy” network setting in the Network System Preference Pane on the Mac
Had the iPhone join the ad-hoc wireless network
Launched iProxy on the iPhone
Observed on the Mac that things weren’t working yet.
Used the Wireless menu to “Disconnect” the Mac from it’s own ad-hoc wireless network
Reconnected the Mac to the ad-hoc wireless network
Now things are working as expected
Let me know if that helps. I will updated the blog post post to note this weird reconnection workaround.
March 11th, 2014 at 9:47 am
@snielsen
Wow, thank you! That is what did it for me, the last part of disconnecting and reconnecting to the ad-hoc wireless network. I was able to get online! Thank you!
March 11th, 2014 at 10:00 am
@Darren No problem. Glad I could help 🙂