SSH dynamic port forwarding (SOCKS) from LAN (behind NAT) to another LAN (behind NAT); middle server with public IP address available
I need advice how to make proper ssh connections.
My network:
I want to be able to view web server content from devices B_1, B_2, B_3 using FF with SOCKS configured on Client A. Note that firewall doesn't allow incoming connections, and that cannot be changed.
I can achieve now something similar by opening single tunnel for each machine (B_1,B_2,B_3), and browse content by typing http://localhost:5678 in FF, without SOCKS on Client A
On Server B -> B_1
ssh -f -n -T -R5678:192.168.1.2:80 user@serverA
On Client A
ssh -L 5678:localhost:5678 user@serverA
I think i need to use ssh -D
on server B to be able to connect to machines B_1,B_2,B_3, just typing IP address in FF with SOCKS set up localhost:5678 on Client A, but i'm doing something wrong, because I can't get it to work.
Any help will be appreciated :)
Solution 1:
Please see how to create a SOCKS proxy with ssh
. This is an excerpt from my answer there:
In general the situation without SOCKS proxy provided by
ssh
is like this:A -> D
where
A
is a client (e.g. web browser),D
is a server (e.g. web server). But with proxy this is as follows:A -> B -> C -> D
where:
A
represents a single client that usesB:$port_number
as SOCKS address; there may be many clients.B
is the machine wheressh -D $port_number C
runs and where the TCP$port_number
listens for incoming connections from anyA
.C
is the$hostname
B
connects to; communication that normally goes toD
fromA
now reachesD
fromC
.D
is any server, it sees communication fromC
and may not be aware thatA
andB
are involved; there may be many servers.Some of these letters may refer to same machine in some particular usage cases. […]
I would like to refer to the linked answer. Unfortunately it uses capital letters A
, B
to name some (abstract) machines; and your question also uses them to name some (real) machines. To mitigate the "collision" I will use standalone letters in the "namespace" of the linked answer; I will use more descriptive terms like "Server B" in the "namespace" of your question.
You want to be able to reach any "Server B_?" from the "Client A". The ultimate server should see the connection coming from the "Server B". This means:
- your "Client A" is
A
, - your "Server B" is
C
, - any "Server B_?" is
D
.
You need to pick B
, so A
can reach B
and B
can reach C
. There are few possible variants:
-
Your "Server B" can be
B
(and still beC
), if only you allowA
to reach it via SSH tunnel(s). In your case this would require chaining two tunnels (or tunneling a tunnel). There is simpler alternative, therefore I won't elaborate (yet). -
Your "Server A" can be
B
, if only you allow it to reach the SSH server onC
via SSH tunnel. This requires the SOCKS proxy on "Server A" to be reachable from "Client A" (i.e.A
), so you need to make it publicly available or to use another tunnel. Still not simple, I won't elaborate. -
Your "Client A" can be
B
(and still beA
), if only you allow it to reach the SSH server onC
via SSH tunnel(s). Let's do this:# on Server B ssh -R 5678:localhost:22 userA@serverA
This makes the SSH server of the "Server B" (i.e.
C
) available asserverA:5678
. Assuming you can open this TCP port on the "Server A", now you can reachC
fromB
:# on Client A ssh -D 1234 -p 5678 userB@serverA
Yes, you specify
userB
because it's "Server B" you're really connecting to; use credentials valid for "Server B".Now the browser(s) on Client A (i.e.
A
) should uselocalhost:1234
as SOCKS proxy. To reach "Server B_?" a browser should probably use URLs as if the browser was on "Server B" (see If I am using SSH for a SOCKS proxy, do DNS connections go through it?).Note the SSH server of the "Server B" is now publicly available as
serverA:5678
. I mean if an attacker wants to target the "Server B" and findsserverA:5678
then their task will be easier than when the "Server B" was totally hidden behind NAT.With yet another tunnel (so two chained tunnels in total; or a tunneled tunnel) one can avoid exposing the SSH server of "Server B" to public. The whole setup will be similar to (1) and the difference will be in what is tunneled and which machine acts as
B
. For completeness let's do this as variant 4 below. -
"Client A" as
B
(and still asA
), without exposing the SSH server of "Server B" thanks to chained tunnels:# on Server B ssh -R 5678:localhost:22 userA@serverA
# on Client A ssh -L 5678:localhost:5678 userA@serverA
This makes the SSH server of the "Server B" (i.e.
C
) available aslocalhost:5678
on "Client A" (i.e.B
). So like in (3) you can reachC
fromB
, this time like this:# on Client A ssh -D 1234 -p 5678 userB@localhost
The browser(s) on "Client A" (i.e.
A
) should uselocalhost:1234
as SOCKS proxy. From their point of view this variant is exactly like the previous one.