Here's a diagram that might help you to understand how everything is arranged. untunnel runs on localhost, and untunnel --server runs on the tunnel machine. Clients then connect to the server sockets on untunnel on localhost (these clients can be located anywhere on localhost's network), and untunnel forwards all data received on its sockets through the tunnel connection to the untunnel --server on the tunnel machine. untunnel --server sends back data received from the target hosts, and untunnel relays back to the clients. > client 1 ---. : untunnel : untunnel --server : .--> host 1 | : ~~~~~~~~~~~~~~~~~~~~~ : ~~~~~~~~~~~~~~~~~~~~~ : | `----> server -. : .- target -----' client 2 --------> server -+- tunnel ----> remote -+- target --------> host 2 .----> server -' : `- target -----. | : : : | client 3 ---' : : : `--> host 3 < client --> server: connect ~ When a client opens a connection to a server socket on untunnel, untunnel attempts to relay that connection to one of the destination hosts: > client connects. server accepts. tunnel sends "open ID HOST:PORT". remote receives. target connects. host accepts. remote sends "open ID". tunnel receives. client: [connect] tunnel: "open ID HOST:PORT" target: [connect] remote: "open ID" < untunnel knows what HOST:PORT to send to untunnel --server because each of its server sockets is associated with a destination host using the -L command-line switch: -L LPORT:HOST:PORT. Here, LPORT is the port number to which the server socket is bound, and HOST:PORT are passed directly to untunnel --server. If untunnel --server reports failure to untunnel, then the client connection is dropped. > client --> server: connect tunnel --> remote: send "open ID HOST:PORT" target --> host : connect *connect failure* remote --> tunnel: send "close ID" < client --> server: send [binary data] ~ vim: set ts=4 sts=4 sw=4 tw=80 et ft=help: