Setting up SSH via USB connection on macOS

December 28, 2014 3 minute read

This is an archive of a post from the sharedInstance tweak development blog, originally written by Alex Hamilton. More up to date information can be found at The Apple Wiki.

When developing tweaks (or making themes, for that matter), it is often annoying to wait for files to copy (and commands to execute) over Wi-Fi - it tends to be very slow and sometimes unreliable, and one must keep track of IP addresses and such (even if they use a hosts file to map custom hostnames) in order to accomplish it. This annoyance can be greatly relieved by creating a local tunnel over a USB connection to the target device, and using that to SSH to the device much more quickly and reliably. In this tutorial, we will cover how to set up your Mac (not PC, sorry - I am not knowledgable enough to write on this) so that port 2222 is forwarded to port 22 on whatever device is plugged in. This service will be started automatically and will run in the background at all times, out of sight and out of mind.

First things first, make sure you have a recent version of usbmuxd installed, as well as its utilities. You can do this easily with Homebrew:

brew install usbmuxd

Now, create a new file named net.sharedinstance.tcprelay.plist in ~/Library/LaunchAgents. Inside this file, put the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>net.sharedinstance.tcprelay</string>
	<key>KeepAlive</key>
	<dict>
		<key>NetworkState</key>
		<true/>
	</dict>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/local/bin/iproxy</string>
		<string>2222</string>
		<string>22</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
</dict>
</plist>

If you have Homebrew installed somewhere other than the default, make sure to change the first item in the ProgramArguments array to reflect that. Then, give the plist appropriate permissions - chmod 0644 ~/Library/LaunchAgents/net.sharedinstance.tcprelay.plist, and load this launch agent we have created - launchctl load ~/Library/LaunchAgents/net.sharedinstance.tcprelay.plist.

From now on, the relay we have set up will always be running the background once you log in. Try it out now with ssh -p 2222 mobile@localhost.

If you use this with multiple devices, you’ll notice a problem: you’ll get a scary host key changed warning:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.

The trick to avoiding this is to set the known hosts file to /dev/null when you’re connecting to localhost:2222. Create ~/.ssh/config if you don’t already have it and add the following:

Host local
	User root
	HostName localhost
	Port 2222
	StrictHostKeyChecking no
	UserKnownHostsFile=/dev/null

You can now use ssh local no matter what device is plugged in.

To use this with Theos, you can export the IP to the host alias and the port to 2222:

export THEOS_DEVICE_IP=local

It would be ideal to also put this in your shell’s profile script (~/.bash_profile, ~/.zshrc, etc) so it’s set by default and you don’t have to worry about it.

Plug in a jailbroken iOS device, copy your SSH key to it if you haven’t already…

ssh local 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub

…and enjoy the blazingly fast transfer speed! Isn’t this much better than boring ol’ Wi-Fi?