linux下通过ssh做反向代理
2013-04-20 20:18:49 阿炯

通过SSH隧道建立SOCKS服务器
如果我们需要借助一台中间服务器访问很多资源,最好的方法是使用SSH客户端为我们提供了通过SSH隧道建立SOCKS服务器的功能。

通过下面的命令我们可以建立一个通过123.123.123.123的SOCKS服务器。
ssh -N -f -D 1080 123.123.123 -p22 # 将端口绑定在127.0.0.1上
ssh -N -f -D 0.0.0.0:1080 123.123.123.123 -p22 # 将端口绑定在0.0.0.0上

通过SSH建立的SOCKS服务器使用的是SOCKS5协议,在为应用程序设置SOCKS代理的时候要特别注意。这里我们用到了SSH客户端的三个参数,下面我们做出解释:

-N 告诉SSH客户端,这个连接不需要执行任何命令。仅仅做端口转发
-f 告诉SSH客户端在后台运行
-L 做本地映射端口,被冒号分割的三个部分含义分别是
 需要使用的本地端口号
 需要访问的目标机器IP地址(IP: 234.234.234.234)
 需要访问的目标机器端口(端口: 23)


最后一个参数是我们用来建立隧道的中间机器的IP地址(IP: 123.123.123.123)

'-L'参数的行为:'-L X:Y:Z'的含义是:将IP为Y的机器的Z端口通过中间服务器映射到本地机器的X端口。当这条命令成功执行之后,我们已经具有绕过公司防火墙的能力了。但较长时间不使用代理时或代理流量异常时,都会报一些错误到终端上:
channel 5: open failed: connect failed: Connection timed out
channel 1: open failed: connect failed: Connection timed out

文章下面将会给出解决办法。

查看隧道状态

有些时候隧道会因为一些原因通信不畅而卡住而假死,例如:由于传输数据量太大,被路由器带入stalled状态。这种时候,往往SSH客户端并不退出,而是卡在那里。一种应对方法是,使用SSH客户端的'ServerAliveInterval'和'ServerAliveCountMax'选项。第二种方法是借助于Autossh工具。

'ServerAliveInterval'会在隧道无通信后的一段设置好的时间后发送一个请求给服务器要求服务器响应。如果服务器在'ServerAliveCountMax'次请求后都没能响应,那么SSH客户端就自动断开连接并退出,将控制权交给你的监控进程。这两个选项的设置方法分别是在ssh时加入'-o ServerAliveInterval=n'和'-o ServerAliveCountMax=m',其中n, m可以自行定义。

如何将端口绑定到非回环地址上

使用上面的方法,映射的端口只能绑定在'127.0.0.1'这个接口上,也就是说,只能被本机自己访问到。如何才能让其他机器访问这个端口呢。我们可以把这个映射的端口绑定在'0.0.0.0'的接口上,方法是加上参数'-b 0.0.0.0',同时还需要打开SSH服务器端的一个选项('GatewayPorts')。默认情况下它应当是被打开的,如果被关闭的话,可以在'/etc/sshd_config'中修改'GatewayPorts no'为'GatewayPorts yes'来开启它。

建立 SSH Tunneling Proxy

SSH Tunnel 属于port forwarding, 它建立在ssh连接上的一个加密的通道,利用它可以传输没经加密的数据从而达到安全的目的。创建了SSH Tunnel之后,你不用直接去访问远程的服务(假使你是连接某个远程服务),相反你访问你本机的某个端口,而SSH Client就会把你的数据通过已建立的加密通道转发到远程主机的目的端口去。

在使用客户端连接 SSH Tunneling Proxy 之前,我们必需先通过相应的工具建立 SSH 隧道,常用的工具有原生的 SSH 命令、 AutoSSH 及 Plink 等。

原生 SSH
在终端下输入如下命令

ssh -N -v user@hostip -D 127.0.0.1:7070
把其中的 user , hostip 替换成你自已的内容。

第一次运行此命令需要输入 yes 来接受证书,最后输入 SSH 密码。如果你不想每次都输入密码的话,可以采用证书认证方式。

ssh自动登录配置

AutoSSH
AutoSSH 的使用方法和 SSH 类似,只是它提供了断线自动连接功能,这样就不必每次重新输入命令了。而且还可以解决超时断

autossh -M 2000 -N -v  user@hostip -D 127.0.0.1:7070

Plink
Plink 最大的好处在于可以指定密码,不必采用证书方式就可以不输入密码建立链接了。

plink -N -v user@hostip -D 127.0.0.1:7070 -pw password
把其中的 user ,hostip , password 替换成你自已的内容。

使用Autossh配置SSH反向连接(Reverse Connection)

A要控制B

A主机:外网,ip:123.123.123.123,sshd端口:2221

B主机:内网,sshd端口:2223

无论是外网主机A,还是内网主机B都需要跑'ssh daemon'。

1.1.首先在B上执行
$ ssh -NfR 1234:localhost:2223 user1@123.123.123.123 -p2221

将A主机的1234端口和B主机的2223端口绑定,相当于远程端口映射(Remote Port Forwarding)。这里每次需要输入A主机user1的登陆密码,当然也可以使用key-autologin方式。

1.2.这时在A主机上sshd会listen本地1234端口
$ ss -ant
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      128               127.0.0.1:1234                     *:*

1.3.像平时一样连接到A主机的1234端口就可以控制内网B主机了
$ ssh localhost -p1234

2、一开始提到,这种反向连接(Reverse Connection)不稳定,可能随时断开,需要内网主机B再次向外网A发起连接,这时需要用工具帮你在内网B主机执行这条命令,它就是Autossh

在此之前还要解决之前的一个问题,那就是每次内网主机B连接外网主机A时都需要输入密码,这个问题ssh本身是提供另外一种验证方式——通过密钥验证用户身份,实现自动登录。

2.1.在内网B主机上生产公钥和私钥
ssh自动登录配置

2.3.再来看看Autossh的用法
$ autossh -M 5678 -NR 1234:localhost:2223 user1@123.123.123.123 -p2221

比之前的命令添加的一个'-M 5678'参数,负责通过'5678'端口监视连接状态,连接有问题时就会自动重连,去掉了一个'-f'参数,因为'autossh'本身就会在'background'运行。

总结
由于SSH隧道也使用了SSH加密协议,因此是不会被防火墙上的内容过滤器监控到的。也就是说一切在隧道中传输的数据都是被加密的。当然,离开隧道后的数据还是会保持自己原有的样子,没有加密的数据还是会被后续的路由设备监控到。