You're at home, and you want to mount a disk from a Mac at work onto your Mac at home, but work has a firewall. Your attempts to use the afp file serving protocol are thwarted because the afp port (548) is blocked.
What can you do? Notice that in the above diagram, the firewall does not block ssh connections. If this is true in your case, the easy answer is that you should be able to make a tunnel with ssh to forward your connection. You start an ssh to the remote host, and tell ssh to forward some random local port (for example, 15548) to the remote host's 548 port. Then instead of trying to open afp to the remote host, you open afp to the localhost, but specify the unuual port. Ssh takes care of the rest.
Under Tiger, this worked just fine. But if the remote host is running Leopard, there seems to be a problem. Leopard apparently won't accept connections to the afp server from itself (when you use ssh tunneling as in the above example, ssh on the remote host end effectively starts a connection from the remotehost back to the remotehost to complete the tunnel).
If your local system is also Leopard, you get a message with "error -36" in it. If your local system is Tiger, then the message will be a complaint about looking up "localhost:15548". But in both cases, the problem is at the remote host end. There's an easy solution, but there has to be more than one computer at the remote host end, which we'll call the third host (and it doesn't have to be running afp, and doesn't even need to be a mac).
Look carefully at the ssh command in the above figure. We are still setting up the tunnel (the -L option) to remotehost. But we are not logging in to remotehost, we are logging into thirdhost. The forwarding still works - ssh on thirdhost knows to forward incoming tunnels from 15548 to remotehost port 548. This makes Leopard happy.
There is a simple two-host solution for afp tunneling to Leopard, described in the next section.
In the second diagram above, my tunnel sets the remote end to point to "remotehost", i.e. the actual hostname and IP address of the remote host. When ssh forwards a connection, it remote ssh end start up a connection from remotehost, back to remotehost. This is what upsets Leopard. It's happy to receive a local mount request going through the "localhost" name and address (127.0.0.1). But it gets upset if a local connection goes through "remotehost". So the solution is:
That looks odd because there's two different localhosts in there. It's important to realize that they refer to two different machines. The localhost in the ssh command is actually "localhost" on the remote host. ssh sets up the tunnel to remotehost, and on the remote end, forwards things to whatever there is called "localhost". Meanwhile, when we open the afp connection to localhost, it's localhost on "myhost", in other words it really is the local host, to the starting end of the ssh tunnel.
This is actually the simplest way to set up most tunnels, and probably should be the default procedure. But you never know when some operating system for whatever reason is going to work one way, and not the other, so it's worth trying both.
Just to make things more complicated, the local end of the ssh connection can be bound to either the localhost address (the default method), or to the hostname of the local system. Binding to the hostname address is necessary for shared tunneling, described below.
For three-party tunneling, the remote end has to use a hostname/IP address, because the tunnel does not go to the localhost system at the remote end of the ssh.
myhost$ ssh -L 15548:remotehost:548 -f -N user@thirdhost myhost$ ssh -L 15548:remotehost2:548 -f -N user@thirdhost bind: Address already in use channel_setup_fwd_listener: cannot listen to port: 15548 Could not request local forwarding. myhost$ ps -ax | grep ssh 13599 ?? 0:00.02 /usr/bin/ssh-agent -l 43210 ?? 0:00.00 ssh -L 15548:remotehost:548 -f -N user@thirdhost 43212 ?? 0:00.00 ssh -L 15548:remotehost2:548 -f -N user@thirdhost 61158 ?? 0:00.06 /usr/sbin/sshd -i 61184 ?? 0:00.43 /usr/sbin/sshd -i 43226 ttys000 0:00.00 grep ssh myhost$ kill 43212
You may not like these backgrounded forever running ssh processes, because it's easy to forget they're there, and it's a nuisance to have to kill them by hand. The simplest alternative is to take out the -f (background) and -N (no command) options. You'll get a regular ssh shell login. When you're done, just exit, and the tunnel goes away too (eventually - the ssh actually keeps running until there are no active tunnels).
But that may not be so great either. You could easily use the ssh login, and forget that it has a tunnel attached (there are ssh escape sequences to find such things, but why bother?). Maybe you think of a tunnel as a one-shot deal, you want to use the tunnel once, and have the tunnel go away. If this is your desire, you can create ssh connections that are good for one connection or one minute (whichever is longer) by doing this:
myhost$ ssh -L 15548:remotehost:548 -f user@thirdhost sleep 60The remote command sleeps for 60 seconds, and then exits. But it only exits if there is no active tunnel. So that gives you one minute to connect, and then when you're done using the connection, it disappears automatically.
So here goes. Let's suppose you have a tunnel set up on myhost as shown above. If you add "-o 'GatewayPorts yes'" to the command, then other hosts can share this tunnel:
myfirsthost$ ssh -o 'GatewayPorts yes' -L 15548:remotehost:548 -f -N user@thirdhost myhost$ open afp://localhost:15548/ myhost$ ssh myotherhost myotherhost$ open afp://myhost:15548/And away we go. Now both myhost and myotherhost are mounting a filesystem from remotehost, and they're using the same tunnel to do it.
Just for completeness, the GatewayPorts option works by listing for connections to the tunnel on the "myhost" hostname and address, in addition to "localhost". Normally, with it only listing on "localhost", there's no way for other machines on the network to connect to that address (if they tried, they'd get their own localhost).
At 2012/10/04 16:35|
Brilliant, thank you for documenting this. I forgot that OS X would simply allow the AFP client to map to another port just by putting it into the URL. It was a lot cleaner than mapping the remote server to the local port 548 with sudo.|
Add a comment
More Mac OS X Stuff
||Send Me Email|