(I don't have a
/dev/tcp device on my system; however
bash seems to have some built-in handling for it, allocating a tcp socket connected to the following
So, your ssh proxy command securely runs a shell on
gatewayserver which does:
i.e. attach a socket on filedescriptor 3 (connected to the
cat <&3 & cat >&3; kill $!
which is a way to have a bidirectional redirection (using two separate processes) between the couple of filedescriptors
1(output), and filedescriptor
3(input and output). The
kill $! is there to kill the background process
cat <&3 after the other process
cat >&3 has returned.
All this is just some equivalent of a more standard:
ProxyCommand ssh gatewayserver "tcpconnect targetserver port"
bash) features instead of the
Some more details:
The proxy command used by ssh is there to define how to connect to the remote host
targetserver (encryption is not really needed there because ssh protocol will be used over this channel). In our case, we want to establish the connection to this target host trough
gatewayserver (probably because a firewall prevents to connect to
So a process
ssh gatewayserver 'exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!'
is started and:
1 (a.k.a. standard output) will be used by an ssh client to send data to the target host.
0 (a.k.a. standard input) will be used by an ssh client to read data from the remote host.
ssh gatewayserver is used to first connect to the gateway which will be the first hop. A new shell is started on this host, and this
ssh instance will relay fd
1 of the process on the origin host to fd
1 of the shell running on gateway host. The command executed by this shell is:
exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!
exec without a command won't execute anything, it will just apply the following redirections the shell itself. Usual redirections are:
n>file to redirect fd
file (open for writting only,
1 if ommited).
n<file to redirect fd
file (open for reading only,
0 if ommited).
n<>file to redirect fd
file (open for reading and writting).
- when specified as
n<>&m, the fd
n is redirected to the file previously pointed to by fd
Here the following is used:
This will redirect a newly created fd
3 to some very special file
/dev/tcp/targetserver/22 (which is not really a file, but something bash understands natively). Here, bash creates a socket (special file which uses the tcp protocol) to talk to
targetserver on port
22 (Where we expect to find a
sshd server), and this file is open (read&write) on fd
Now we need to "pump" data on fd
0 (data from client) and send it to fd
3 (connected to the target server).
We also need to assure backward communication by "pumping" data on fd
3 and sending it back to fd
1 (result for client).
Those two "pumps" are set up using two
cat <&3 (which reads from the shell's fd
3 and write to the shell's fd
cat >&3 (which reads from the shell's fd
0 and write to the shell's fd
cats must be run in parallel, so one needs to be backgrounded. Here, we want the one that reads on fd
0 (which will probably be a tty) be the one left in the foreground. This gives:
cat <&3 & #run in the background
cat >&3; kill $!
kill $! is there to kill the background process (
$! expands to the pid of the last backgrounded process). This way when the client hangs up, the foreground process terminates, the kill is performed, and the last process is terminated too.
That's it! We've made the bridge:
origin host —(ssh)→ gateway —(pumps+socket)→ targetserver(port 22)
ssh user@targetserver on the origin host will be able to connect to the target host through this bridge!