6

(Redirected from networkengineering.stackexchange)

I have two Raspberry Pis on my network - let's call them Pi and Rho.

I'm trying to set up port forwarding via ssh tunnel between them, such that an application can connect to a port on Rho and get results from a server listening on a port on Pi (my eventual goal is actually to set up port forwarding such that a host on a different network could get access to a Samba share on Pi via an ssh connection to Rho, without my having to entirely open a firewall port to Pi).

Pi's IP in my LAN is 192.168.42.69, and Rho's is 192.168.42.112 - these are the IPs that I ssh to from my local network to connect to them.

In order to test this, I have started a minimal Python server (with SimpleHTTPServer) on Pi's port 8000, and run sudo ssh -L 140:localhost:8000 root@192.168.42.69 -N on Rho. When I curl localhost:140 or curl 127.0.0.1:140 on Rho, I get the response I expect. However, when I curl 192.168.42.112:140 on Rho, I get a connection refused; verbose output below:

$ curl -vvv 192.168.42.112:140
* Expire in 0 ms for 6 (transfer 0x2cd880)
*   Trying 192.168.42.112...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x2cd880)
* connect to 192.168.42.112 port 140 failed: Connection refused
* Failed to connect to 192.168.42.112 port 140: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 192.168.42.112 port 140: Connection refused

What is the reason for this discrepancy?

Having checked this other question, I confirmed that the environment variable HTTP_PROXY is not set on Rho, nor is NO_PROXY.

7

In your ssh command, you are not specifying a bind_address for your -L option.

According to man ssh:

By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of localhost indicates that the listening port be bound for local use only, while an empty address or * indicates that the port should be available from all interfaces.

To allow connections on all interfaces and not just localhost (which is an alias for 127.0.0.1, the address of the loopback interface), specify a bind_address of 0.0.0.0 in your -L option, e.g.

sudo ssh -L 0.0.0.0:140:localhost:8000 root@192.168.42.69 -N

If you would prefer it listen on a particular IP, you can specify it instead of 0.0.0.0.

| improve this answer | |
  • TIL, thanks! An alternative I found was to use sudo ssh -o GatewayPorts=yes -L 140:localhost:8000 ... – scubbo Mar 29 at 1:31
5

This is what man 1 ssh states:

-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket

Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side. […]

By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of localhost indicates that the listening port be bound for local use only, while an empty address or * indicates that the port should be available from all interfaces.

GatewayPorts mentioned is the one from ssh_config (not the one from sshd_config, this one is for -R). From man 5 ssh_config:

GatewayPorts

Specifies whether remote hosts are allowed to connect to local forwarded ports. By default, ssh(1) binds local port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. GatewayPorts can be used to specify that ssh should bind local port forwardings to the wildcard address, thus allowing remote hosts to connect to forwarded ports. The argument must be yes or no (the default).

Your command

ssh -L 140:localhost:8000 root@192.168.42.69 -N

does not specify bind_address, it qualifies to "by default". It looks like GatewayPorts for ssh is no.

Note "an empty address" looks differently: -L :140:localhost:8000. The extra colon matters. This variant does specify bind_address as an empty string, while -L 140:localhost:8000 you used does not specify bind_address at all.

To bind to all interfaces use an empty address (-L :140:localhost:8000) or * (in a shell you should quote it, e.g. -L '*':140:localhost:8000).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.