SSH 访问 NAT 路由器后面的办公室主机

rit*_*ter 41 linux firewall ssh nat ssh-tunnel

我想从家里访问我办公室 linux 主机的 ssh 端口。不幸的是,主机位于 NAT 路由器后面。因此,IP 地址不是公开可用的。然而,可以访问另一个互联网主机(服务器),不幸的是,它只是非 root 访问。经过一段时间的搜索,我没有找到合适的解决方案。

以下设置:

  • 位于 NAT(IP 非公共)之后的办公室 PC(linux,root 访问权限),但可以完全访问 Internet。
  • 服务器 PC(Linux,无根访问权限)静态和公共 IP 以及完整的 Internet 访问权限。
  • Home PC (linux, root access) behind NAT (IP not public) but full Internet access.

Possible connections: Office PC --> Server <-- Home PC

Not possible: Office PC <-X- Server -X-> Home PC

Neither the Home PC, nor the Server can initiate access to the Office PC. But both the Office PC and the Home PC can initiate connections to the Server.

Reverse SSH tunnel not possible: I tried a method called reverse ssh-tunnel. Unfortunately this requires GatewayPorts on Server set to "yes" in /etc/ssh/sshd_config, where I have no root access.

In principle it should be possible:

0) On the Server I start a userspace program which listens on 2 ports (1 incoming, 1 outgoing)

1) On my office PC I run a another program which keeps a TCP connection open to the outgoing port on the server.

2) From home I connect to Server's incoming port.

There should be a standard solution for this out there.

What is the quickest and cleanest solution to solve this?

Frank

Pis*_*ing 37

youatwork@officepc$ autossh -R 12345:localhost:22 notroot@serverpc
Run Code Online (Sandbox Code Playgroud)

Later:

you@homepc$ autossh -L 23456:localhost:12345 notroot@serverpc

you@homepc$ ssh youatwork@localhost -p 23456
Run Code Online (Sandbox Code Playgroud)

What you could do is this: in step 1 forward a remote port from the office PC to the server (12345 is used as an example, any port >1024 should do). Now connecting to 12345 on the server should connect you to port 22 on officepc.

In step 2, forward the port 23456 from your home machine to 12345 on the server (whence it gets forwarded to officepc:22, as set up in step 1)

In step 3, you connect to the local port 23456 with your office PC login. This is forwarded by step 2 to port 12345 on your server, and by step 1 to your office PC.

Note that I'm using autossh for the forwardings, as it's a ssh wrapper which automatically reconnects the tunnel should it be disconnected; however normal ssh would work as well, as long as the connection doesn't drop.

There is a possible vulnerability: anyone who can connect to localhost:12345 on serverpc can now connect to officepc:22, and try to hack into it. (Note that if you're running a SSH server, you should anyway secure it above the basic protections which are on by default; I recommend at least disabling root login and disabling password authentication - see e.g. this)

Edit: I have verified this with the same config, and it works. GatewayPorts no only affects the ports that are open to the world at large, not local tunnels. This is what the forwarded ports are:

homepc:
  outgoing ssh to serverpc:22
  listening localhost:23456 forwarded through ssh tunnel
serverpc:
  listening ssh at *:22
  incoming localhost ssh tunnel (from homepc) forwarded to localhost:12345
  listening localhost ssh tunnel (from officepc) forwarded from localhost:12345
officepc:
  outgoing ssh to serverpc:22
  incoming localhost through ssh tunnel (from serverpc) forwarded to localhost:22
Run Code Online (Sandbox Code Playgroud)

So, as far as the network stack is concerned, it's all local traffic on the respective loopback interfaces (plus ssh connections to serverpc); therefore, GatewayPorts is not checked at all.

There is, however, the directive AllowTcpForwarding: if that is no, this setup will fail as no forwarding is allowed at all, not even across the loopback interface.

Caveats:

  • if using autossh and recent ssh, you may want to use ssh's ServerAliveInterval and ServerAliveCountMax for keeping the tunnel up. Autossh has a built-in check, but apparently it has some issues on Fedora. -M0 disables that, and -oServerAliveInterval=20 -oServerAliveCountMax=3 checks if the connection is up - tries each 20 sec, if it fails 3x in a row, stops ssh (and autossh makes a new one):

    autossh -M0 -R 12345:localhost:22 -oServerAliveInterval=20 -oServerAliveCountMax=3 notroot@serverpc
    
    autossh -M0 -L 23456:localhost:12345 -oServerAliveInterval=20 -oServerAliveCountMax=3 notroot@serverpc
    
    Run Code Online (Sandbox Code Playgroud)
  • it might be useful to restart ssh tunnel if the forward fails, using -oExitOnForwardFailure=yes - if the port is already bound, you might get a working SSH connection, but no forwarded tunnel.

  • using ~/.ssh/config for the options (and ports) is advisable, else the command lines get too verbose. For example:

    Host fwdserverpc
        Hostname serverpc
        User notroot
        ServerAliveInterval 20
        ServerAliveCountMax 3
        ExitOnForwardFailure yes
        LocalForward 23456 localhost:12345
    
    Run Code Online (Sandbox Code Playgroud)

Then you can use just the server alias:

    autossh -M0 fwdserverpc
Run Code Online (Sandbox Code Playgroud)

  • @Frank:实际上,我不这么认为:`GatewayPorts no` 限制打开的端口只能在环回接口上访问;请注意,在第 2 步中,您在环回接口上转发(实际上,两个转发都是“仅本地主机”),因此这可能会起作用(sshd 配置中的“AllowTcpForwarding no”会破坏这一点)。 (3认同)
  • @弗兰克:是的,确认。这甚至适用于`GatewayPorts no`;编辑了答案。请注意,还有其他指令(例如“PermitOpen”和“AllowTcpForwarding”)可以破坏此设置:http://www.manpagez.com/man/5/sshd_config/ (3认同)