SSH gateway: how to understand ssh -L when remote comes first?
I understand some ssh forwarding basics, but this SuperUser post seems backwards to me. In other words, with 2 hosts, this…
ssh -L 0.0.0.0:10022:localhost:22 root@A
…seems to allow a connection from localhost to A. But with 3 hosts, this…
ssh -L 0.0.0.0:10022:A:22 root@B
…allows localhost to A though B? Why not localhost to B through A?
The ssh man page seems to describe the 2-hosts option, not the 3-hosts option:
-L [bind_address:]port:host:hostport
Whenever a connection is made to the local port or socket, the connection is forwarded over the secure channel, and a connection is made to either
host
porthostport
, or the Unix socketremote_socket
, from the remote machine.
Solution 1:
It's not clear to me what your (mis)understanding really is. I guess the confusion might be because of the word "localhost".
Localhost is a relative term. By definition, in context of any machine localhost
should refer to this machine exactly. Practically every Linux resolves localhost
as IP address 127.0.0.1
(I put IPv6 aside) thanks to a proper entry in /etc/hosts
file. 127.0.0.1
should be assigned to a loopback interface.
In the linked answer most occurrences of the word localhost
refer to the machine (of three) that is neither host1
nor host2
; this is the local machine where commands are invoked. Similarly, when you say "localhost" you probably mean neither A
nor B
. From now on let's call this local computer the client.
Basically you run this on the client:
ssh -L bind_address:port:host:hostport user@server
There are two computers involved: the client and the server. Certain parts of the command are valid in context of either the client or the server.
-
ssh -L
is the executable with option that the client understands (the server may not havessh
at all). -
server
is the address of the server from the client's point of view (server may not even be aware it has such-and-such address or name). -
user
is a username existing on the server (it may not exist on the client). -
bind_address
andport
are respectively the address (interface) and TCP port on which the client'sssh
will listen (I don't know if these parameters are even passed to the server at all, the server doesn't need them). In your case0.0.0.0
means "every available interface". -
host
andhostport
are respectively the address and TCP port to which the server should send packets tunneled from the client. These parameters are for the server;host
is resolved on the server. From the client's point of viewhost
may be an invalid address or it may resolve to something completely different – it doesn't matter because the client doesn't resolve it at all;host
is just a character string passed to the server, it means nothing more on the client's side.
This means if there's a literal localhost
as this host
parameter, it is "localhost" from the server's point of view, i.e. the server itself. It doesn't mean "the client".
With this knowledge let's analyze your examples.
ssh -L 0.0.0.0:10022:localhost:22 root@A
This captures everything that enters the TCP port 10022
of the client; captured packets will be recreated on the server A
and destined to localhost:22
, but localhost
on the server means "the loopback interface of the server A
itself".
ssh -L 0.0.0.0:10022:A:22 root@B
This captures everything that enters the TCP port 10022
of the client; captured packets will be recreated on the server B
and destined to A:22
from there.
Indeed it can be described as "localhost to A though B", where "localhost" means the client.