SSH tunneling redux

Years ago I wrote a post about how I access services on my office computer from my laptop. My setup has changed a bit since then, so it seemed worthwhile to write a short update.

My office computer isn’t generally accessible from the internet, but the office router does have a permanent public IP number and it’s configured to forward calls on the SSH port to my computer, which has an SSH server running by enabling Remote Login in the Sharing Preference Pane. Through a system called SSH tunneling, I can securely access services that run on my office machine by piping them through the SSH protocol. Using a service remotely from my laptop generally consists of two steps:

  1. Running a script on my laptop that sets up the tunnel.
  2. Accessing the remote service through whatever application would access it locally.

There are three services I use this way, and therefore three tunneling scripts.

workwiki

I have an administrative wiki running on port 2500 on my office computer. The wiki has pages with information on the equipment we own, commonly- and uncommonly-purchased supplies (with links to online stores), important phone numbers for the services we use, and anything else I want to be able to look up quickly. Most of the times I need the wiki, I’m sitting in my office, but sometimes it’s helpful to be able to get at it from home or the road.

The script that creates the SSH tunnel from my office computer to my laptop is called workwiki and it looks like this:

bash:
#!/bin/bash

ssh -C -L 2500:127.0.0.1:2500 -N drang@1.2.3.4

It’s just a one-liner with some special options to the ssh command. The -C tells it to compress the data on the remote end and uncompress it locally. The -L option and its argument tell ssh to bind port 2500 on my local machine (which always has an IP number of 127.0.0.1) to port 2500 on the remote machine. The -N option tells ssh to just do the forwarding and not execute commands on the remote machine. Finally, there’s my login name and the public IP address for my office computer. Obviously, the drang@1.2.3.4 is fake; the real version of workwiki has my real login name and IP address.

I run workwiki from a Terminal window on my laptop, and then access the wiki pointing my browser to localhost:2500, just as I would if I were sitting at my office Mac. When I’m done with the wiki, I type ⌃C in the Terminal to stop workwiki and close off the tunnel.

workscreen

Occasionally I really need to look at office computer’s screen. For that I use a combination of the Screen Sharing application and a tunneling script called workscreen:

bash:
#!/bin/bash

ssh -C -L 6900:127.0.0.1:5900 -N drang@1.2.3.4

This is also an ssh one-liner. The only difference is in the port numbers. Here, we’re forwarding local port 6900 to remote port 5900, which is the port number Apple chose for screen sharing. I chose 6900 for the local port because I didn’t want to interfere with 5900.1

Update 11/11/12
Look in the comments for a script that establishes the tunnel, launches Screen Sharing, and closes the tunnel when Screen Sharing is quit. See also Alan Schmitt’s Keyboard Maestro macro for doing the same thing.

For this to work, my office computer has to have screen sharing already turned on, which I’ve done through the Sharing Preference Pane.

Screen Sharing Preference Pane

After running workscreen, I open Screen Sharing on my laptop by using the Finder’s Connect to Server… command in the Go menu. The address I connect to is vnc://127.0.0.1:6900, the local port that’s being tunneled to my office computer.

Screen sharing local connection

It may seem odd for the “server” in this case to be the local machine, but that’s how it works. Clicking the Connect button launches the Screen Sharing application with the screen of my office computer in the window.

Screen sharing local connection

When I’m done working remotely on my office computer, I quit Screen Sharing and ⌃C in the Terminal to stop workscreen and close off the tunnel.

worktunes

Finally, we have the script I use to connect to the iTunes library on my office machine. This was important when my laptop was an iBook with an 80 GB hard disk, and it’s just as important now that my laptop is a MacBook Air with 128 GB of SSD—neither computer has enough storage to comfortably hold my iTunes library, but I still like to be able to play my music when I’m not at work.

The first step is to configure iTunes at work to share its music and playlists. That’s done in the iTunes Sharing preference.

iTunes Sharing Preferences

To stream music from the office, I need to forward the port used by the Digital Audio Access Protocol (DAAP), the protocol Apple uses for iTunes sharing, and set up a proxy for it. The script that does this is called worktunes.

bash:
#!/bin/bash

ssh -C -L 36890:127.0.0.1:3689 -N drang@1.2.3.4 &
trap "kill $!" SIGINT SIGHUP SIGTERM
dns-sd -P "Office iTunes" _daap._tcp local 36890 localhost.local. 127.0.0.1

The first line should be familiar. It establishes a tunnel from remote port 3689 (the DAAP port) to local port 36890 (chosen not to interfere with the local DAAP port). Once upon a time, that was all I needed, as I then used the Network Beacon application to do the proxying. Unfortunately, Network Beacon is no more, so I had to figure out how to do the proxying in the script itself.

As is often the case, “figuring out what to do” really meant “finding and stealing the work of someone else.” The someone else was Robert Harder, whose script bears an uncanny resemblance to mine. Funny, that.

The proxy is set up by the dns-sd command, which routes all calls to DAAP to the local 36890 port—which, in turn, tunnels them to port 3689 on my office computer. There’s a bit of Unix trickiness in putting the ssh command in the background with the & at the end of its line and then using the trap command to cause it to be killed when the script as a whole is stopped with ⌃C.

After I run worktunes on my laptop, a new item called “Office iTunes” appears in the Shared section of my iTunes sidebar.

iTunes shared libraries

Clicking on it starts a process that loads the metadata from my office iTunes library—which, of course, must be running.

iTunes loading remote library info

The loading takes 15-30 seconds, and when it’s done I have all my playlists from the office machine available. Any song I choose will stream from work to my laptop.


There are, I’m sure, plenty of other services I could access remotely through SSH tunneling, but these are the ones I use. Tunneling is not only useful, it’s one of those things that makes you feel like you’re living in the future.


  1. This is probably unnecessary, as screen sharing is turned off on my laptop, but I didn’t see any reason to take chances. 


13 Responses to “SSH tunneling redux”

  1. Rob Mathers says:

    Tunnels are indeed great. Hadn’t seen them used for iTunes sharing before. Does the dns-sd trap all DAAP traffic? I.e. would it block out any other iTunes shares on your local network?

  2. Jonas says:

    I’m impressed by how elegantly all this can be implemented between OSX machines. I’ve done similar things between Windows and Linux machines and it isn’t remotely as minimal and functional!

    I’m struggling with a similar iTunes syncing problem. I have a large library of audiobooks. Too large to conveniently store on my MacBook Air’s 256 GB SSD. Storing the library on another machine and sharing it doesn’t allow me to sync stuff from the MB Air to my iPhone. Any ideas?

  3. Guillaume Kuster says:

    I’m curious about the benefits of the -C flag. I have read that this was designed for (very) slow dial-up modem connections. Is this really beneficial even with today fast connections ?

  4. Alan Schmitt says:

    This is a very interesting approach to remotely share iTunes libraries, thanks for the tip.

    If I may offer a small refinement for the Screen Sharing part, I have a small Keyboard Maestro macro that launches everything with a keyboard shortcut, then automatically kills the tunnel when I quit Screen Sharing. I described it here: http://blog.petitepomme.net/post/35485335351/ssh-tunnel-and-screen-sharing-through-keyboard-maestro

  5. Dr. Drang says:

    Guillaume,
    I’m suspicious of the value of -C, too. It does seem to make the initial download of metadata from iTunes go faster, but I can’t point to any noticeable benefit beyond that. Feel free to omit it.

    Alan,
    Although I don’t use Keyboard Maestro, the technique you’re using could, I think, be adapted into the workscreen script itself, where running it would establish the tunnel and then launch Screen Sharing. I’ll have to give that a try. Thanks for the tip!

    Rob and Jonas,
    The simple answer to your questions is I don’t know. I haven’t used iTunes sharing beyond what I’ve described here. They seem like easy things to test, though, if you have the right computer and network combination.

  6. Neal Lippman says:

    Great post. I use ssh tunneling regularly to securely access my work computer. I tunnel the ports used by the Windows smb file system. The office is resolutely Windows based, but from home I can mount our network shares as needed via this mechanism.

    The iTune sharing is very helpful. I had not thought to do that, but now I will!

    One question: You appear to create s series of script files, but I assume that you invoke them as needed from a terminal window. I have created all of the necessary ssh tunneling commands as either aliases or shell functions. Do you see a compelling advantage to script files vs alias/shell functions? I’m curious as I don’t see what the advantage would be.

    By having my .bash_profile be a symlink to a file in my Dropbox folder, it is easy to keep all of these various commands consistent across various machines.

  7. Dr. Drang says:

    Neal,
    I write these as scripts because scripts are more flexible. They can be run from the command line, of course, but I often repurpose them to be run from FastScripts. And if you’re a Keyboard Maestro or Quicksilver user, scripts are more adaptable to those environments, too.

  8. Neal Lippman says:

    Thanks for the followup. Makes sense. I haven’t used any form of launcher before, but have been thinking of LaunchBar ever since I started listing to MacPowerUsers and ready MacSparky, so … maybe I’ll repurpose some of my aliases and shell functions as scripts. It would be as easy to keep a scripts folder under Dropbox as to keep my bash_profile there.

  9. Wes Campaigne says:

    Alan, Dr Drang, Simply adding “open vnc://127.0.0.1:6900” to the end of workscreen is enough to automate opening the Screen Sharing client app and getting it to connect through the tunnel.

    Rob, The dns-sd command shouldn’t interfere with anything; it isn’t even trapping traffic. All it’s doing is advertising (via Bonjour) the availability of a shared iTunes library / DAAP server —- in this case, advertising the near end of the tunnel as something to connect to, as it’s known in advance that there’s a library / DAAP server that exists at the other end of the tunnel. (iTunes on the Office computer is busy advertising itself on the other end of the tunnel, but those advertisements aren’t being passed through the tunnel, and even if they were, they wouldn’t help, because they wouldn’t take into account the mangling of ports and addresses that occurs due to the tunnel.)

    Other computers’ iTunes on the local network are free to share and advertise as normal.

  10. Wes Campaigne says:

    Err… using the ‘open’ shell command would depend on backgrounding ssh appropriately. And to really streamline it, you’d still need an alternate means of detecting when the Screen Sharing app stops running to know when to kill ssh.

  11. Dr. Drang says:

    Wes,
    This seems to work:

    #!/bin/bash
    
    ssh -C -L 6900:127.0.0.1:5900 -N drang@1.2.3.4 &
    tunnel=$!
    sleep 3
    open -W vnc://127.0.0.1:6900
    kill $tunnel
    

    The -W option for open is what you were looking for to detect the quitting of Screen Sharing. The three-second delay is probably overkill, but some delay is necessary for the tunnel to get established before Screen Sharing is launched.

  12. Wes Campaigne says:

    Ahh, of course. I’d forgotten that option of the (wonderful, underrated) open command.

  13. Rob Mathers says:

    Thanks for the clarification on what exactly dns-sd does, Wes.