前几天,公司为了加强网络安全,来了个新规定,员工不能直接从自己的电脑连通公司的其他电脑。需要连通那些电脑的话,必须先登录一个 jumpbox,也就是一个中转电脑,然后才能从这个中转电脑去别的地方。
然后,因为这是个中转电脑,是全公司的人共用的通道,而且只是个通道,没打算让您干别的,所以这个中转电脑容量有限,派给每个用户的权限也很低,很多指令不能在上面运行。
这个限制让我干活效率大大降低,有些活根本就没法干了,比如,我定期需要下载十几个G的文件到我自己的硬盘,做分析处理之后,再转存到一个网盘里。有这个中转电脑卡着,我不能直接从那些远程电脑上下载文件。而中转电脑本身没空间存放这么多文件,也不能做那些分析处理的——处理是用 Perl 脚本程序,而这个 jumpbox 不让执行 Perl 脚本程序。
我需要找到一个办法绕过这个中转电脑的限制,让我自己的电脑能直接跟所有那些电脑连通。
于是想到了网络隧道,ssh tunnel。
我以前用过两次tunnel,但都是直接在Putty(ssh 客户端)的图形界面上,按照人家给定的参数设置,就是个傻徒弟学艺,人云亦云,根本就没弄明白这 tunnel 到底是咋能打通一个隧道的。所以现在需要自己设置,就有点茫然。找一些文献看,跟以往一样,99%的电脑技术文献,不论中文的还是英文的,都是堆砌术语不知所云。以前我是看了两眼,觉得文章写得太烂,就懒得看了。这次是给逼到墙角,必须弄明白,只好硬着头皮上下查了一通,好歹看懂了怎么用 tunnel 绕过防火墙这一部分。那么就给总结一下,算是记录一下心得,帮助自己记忆。
tunnel 协议其实有不止一种用途,其中一种(也是最常用的一种)是端口转发(port forwarding)。用过电驴或是电骡的人应该多少都知道端口转发的意思。不过,tunnel 的端口转发还可以分三种亚型,就是正向,逆向(reverse)和动态(dynamic)的。但是后两种都很少用。我这里只说我这次用到的,就是利用正向端口转发功能来绕过网络限制。
我们用一个最容易理解的网络限制来做例子,比较容易说清楚。比如,我们假设您的单位有网络,可以用电脑上网,但是您从单位里面上网,不能访问 www.yahoo.com 这个网站,就是雅虎网站。
然后,您是个很勤奋的人,在家里都有一台电脑可以跟单位电脑联网,这样晚上在家还能加班。因为您家里的电脑也是办公电脑,单位就允许您从办公室电脑连接到家里的电脑,便于交换文件。但是,您家里的电脑是在家里不在单位里,于是它不受单位防火墙的限制,所以它是可以访问雅虎的。
那么,如果您能从单位的电脑那里挖一个网络隧道,穿过单位的防火墙,连接到家里的电脑,这就来到了防火墙之外,就可以利用这个渠道访问雅虎了。
当然,前提是您家里的电脑是支持 ssh, 也就是 secure shell (安全壳层)的,因为我们需要挖的隧道是 ssh tunnel。
这个局面,用图形表示,就是下面这个样子。别的网站可以访问,但是不让访问雅虎(当然这个例子很没道理。不过,用这样简化的例子比较容易理解 tunnel 是怎么打通隧道的)。
如何用ssh隧道绕过防火墙
好了。单位有这个限制,但是呢,咱假设因为工作需要,您必须从办公室的电脑里访问雅虎。那么您就需要从办公室电脑开挖隧道,绕过防火墙的限制,这样才可以访问雅虎。
您可以这么做。在办公室电脑里,打开 Putty (或者随便别的什么 ssh 客户端,比如 Cygwin),敲这个指令:
ssh -L 9001:yahoo.com:80 [email protected]
(连接到 homecomputer.com 的时候会让你敲 user 的密码。注意这个细节。因为这里有登录控制,这个挖隧道的动作并没有破坏系统的安全管理。您必须有登录这个中转电脑的权限才可能挖这个隧道。而您能登录中转电脑就证明了您是合法用户。所以,安全性并没有被打破。)
这里的 -L 是指定本地(就是您正在用的电脑)端口,就是说它后面的9001,意思就是在本地开通这样一个新端口。这个9001端口就是隧道的起点了。端口号之后一个冒号,冒号后面是你这次越狱要去访问的目的地,也就是雅虎。雅虎网址是普通网页,端口号是标准的80,所以第二个冒号后面的端口号是80。
9001是隧道的起点,那么隧道的终点在哪里?
终点就是您家里的那台电脑。怎么指定这个终点?就是在第二个端口号(80)之后敲一个空格,然后再空格后面指定。空格后面的那个 homecomputer.com,就是您家里电脑的IP或者网址。这就是告诉 ssh,这个隧道,从9001这儿开始挖,一直通到 homecomputer.com那儿去。
就是说,语法是这样的:
ssh -L <本地端口号>:<目的网址>:<目的网址端口号> <隧道终点电脑>
(隧道终点电脑这里,如果登录用户名跟您当前用户名一样的话,可以省略。如果不一样,记住要加 “用户名@”。)
终点不用写端口号,是因为,这是一个 ssh 隧道,ssh 隧道的起点可以自行指定一个端口,但是它的终点必须是一个 ssh 服务程序,而 ssh 服务程序规定用22端口,不可能是别的,所以就不需要写了。这就像你打算挖一个隧道通往关押段誉的那个石屋(我说的是《天龙八部》第九回的那个故事),您从哪儿开始挖隧道,可以自己挑地方,但是终点只能是那个石屋,不能是别的。
如果单看这个语法,结构有点“不符合直觉”,因为它先写目的地,然后才写隧道终点。我们如果想象一下这个隧道的走向,它本来应该是这样的:
隧道起点电脑->隧道终点电脑->目的网址
但是 ssh 作者规定了语法是这样,咱也不能跟人吵架,就只能按规定来敲指令了。
这就是建立隧道的方法。就是说,您在办公室电脑里敲了
ssh -L 9001:yahoo.com:80 [email protected]
之后,您就可以在您的办公室电脑访问雅虎了。打开浏览器,在地址栏里输入 http://localhost:9001,浏览器里打开的就是雅虎网页。
为什么?因为,localhost 就是本地电脑,就是您的办公室电脑。您刚才敲的指令,在本地开通了端口9001,这个端口就是隧道的起点。隧道的终点是您家里的电脑。因为您建立了这么一个隧道,您在办公室浏览器里输入 localhost:9001,这个“载入页面”的请求来到端口9001,立刻就会被沿着隧道转发到您家里的电脑里(所以这种技术叫做端口转发)。
家里的电脑受到这个请求之后怎么处理?就是看您指令里中间那一句话:目的网址。您的目的网址是雅虎,所以您家里的电脑收到从这个隧道传过来的访问请求,就直接给转到雅虎那儿去了。
所以您在办公室电脑的浏览器里敲 localhost:9001,实际上打开的却是 www.yahoo.com
这个就是借助隧道绕过防火墙的用法。
从您的办公室电脑到您的家庭电脑那段路,是 ssh 隧道。ssh 隧道是加密的。这也是单位能允许您在办公室电脑和家庭电脑之间连线办公的原因。数据都是加密的,不用担心被窃听。
从您的家庭电脑去访问雅虎那段路,走的是互联网,是大众网络。大众网络里面的数据不加密,如果有人窃听,能看到数据内容。但是访问雅虎不是公务,不会涉及单位机密。那段路加密不加密都无所谓了。
用图形表示,这个隧道大致是这么个样子。
这个就是 ssh tunnel 穿过防火墙的基本原理,就是从受限电脑挖个隧道通到一个不受限电脑,到了不受限电脑就是到了防火墙外面,就可以访问那些不能从防火墙内部直接访问的网站了。
上面这个例子,是借助隧道访问万维网网站。但是 ssh tunnel 并没规定你只能用来访问网站。用端口80的话是访问网站,但是如果指定别的端口,就可以干别的活计。
比如,用来解决我文章最开头说的问题。
这个问题其实也是个防火墙拦截的问题。就是说,咱公司这个新安全政策,其实就是建立了一道新的防火墙,让我们这些普通用户(普通的意思就是没有穿过防火墙的特权)不能直接连通那些服务器。我们只能连接那个jumpbox(中转电脑)。这个jumpbox是在防火墙里面的,所以连接到了jumpbox,就可以不受限制的访问所有其他服务器了。
用比喻来帮助理解的话,就是说,原来所有的服务器都在一个围墙里,不过围墙上有很多门,每个服务器都有自己的门。您有钥匙(密码)就可以进门,进门就可以操纵那些服务器。后来安全部门觉得不放心。因为,这些服务器都是很多职员共用的,所以密码不能总变。制定一个密码就要用很久。这个是违法网络安全常识的。要保证安全,密码必须时时更换。怎么办?安全部门就把围墙上那些门都堵死了,只留下一扇门,这扇门只有您自己进入单位局域网的那个密码才可以打开。打开之后进去是一个平台,从这个平台有很多条通道,能去到各个服务器,不过通道并不是敞开的,也有门,需要用那些服务器自己的密码来开门。有就是说,原来直接开在围墙上的那些门,现在改道了,是从这个入口平台这儿开门。
这个平台就是我说的 jumpbox(中转电脑)。
这种做法有什么优点?这主要是为了加强安全性。因为,打开这个唯一入口的密码,是您进入公司局域网的密码。电脑公司的职员,每个人都有这样的个人密码。打开电脑第一步就必须输入这个密码。这种密码不是共用的,只有您自己知道。这就很难泄露。第二,这种个人的局域网密码是强制更新的,每隔一段时间,系统就会把您的电脑锁定,您必须换一个新密码才能解锁。有这样高度保密的个人密码,围墙留下的这唯一的一扇门就不大可能因为密码泄露而被攻破。这就是公司采用这个新政策的原因。
如果用前面说的例子做比照,我的办公室电脑还是办公室电脑,一样的受防火墙的限制。那个 jumpbox就相当于前面那个例子里我的家庭电脑,因为我可以直接从办公室电脑访问这个 jumpbox,防火墙不阻拦这个。而那些不允许我们访问的服务器,就相当于雅虎网站,因为它们是要被防火墙拦截,不让直接访问的。
我需要的就是用前面说过的方法,建立一个隧道,只不过隧道的那头不是通往家里的电脑,而是通往那个 jumpbox。然后,我挖隧道的目的不是去访问雅虎网页,而是要远程连接那些被禁止直接连接的服务器。
那么我这个隧道应该是这样挖:
ssh -L 9001:banned.com:22 [email protected]
就是说,用 -L 指定在本地电脑(就是办公室电脑)开通端口9001,这个是隧道的起点。隧道的终点是那个 jumpbox,就是那个我可以直接访问的中转电脑——只要是可以不受防火墙限制,能直接访问的电脑,而且上面安装了ssh 服务(sshd)的,都可以用来做隧道终点。
指令的中间一段是那个被禁止直接访问的服务器,banned.com:22。冒号后面是端口。这里用端口22而不是80,是因为,我现在到 banned.com去,不是为了看网页,是要建立 ssh 连接,也就是远程电脑登录连接。端口22是专门做这样的远程连接用的。
隧道挖好了,就可以穿墙了。
怎么穿?首先,您需要另外开一个 ssh 客户端(比如 Putty)。因为刚才这个客户端变成了一个隧道。您不能用隧道来钻隧道。用一个比喻的话,您可以把 ssh 比作一列火车。上面那个指令一敲,您就是把一列火车改装成了一个隧道。要利用这个隧道旅行,您得另外开一辆车。
打开另一个 ssh 客户端窗口之后,您可以敲这个指令:
ssh -p 9001 localhost
注意这个 -p 必须是小写的 p。
这行指令,看起来就是说:用 ssh 连接到本地电脑(就是您正在打字的这台电脑)的端口9001.
敲了这个指令之后,一回车,您就会发现,您现在已经用 ssh 连接到了 banned.com
因为,您刚才建立的这个隧道,把您本地电脑的端口9001给连通到了 jumpbox (中转电脑),然后中转电脑看到您那个隧道指令的中间一句话是 banned.com:22,就把您的 ssh 请求给转发到了 banned.com 的端口22 .
端口22是 ssh 端口,您能链接到 banned.com 的端口22,就建立了远程连接,就可以对远程电脑(banned.com)做任何事,包括发指令,下载,上传,就好像是对本地电脑操作一样。
我需要的就是这个。建立了这样的隧道之后,我就不需要先登录 jumpbox,然后再登录防火墙后面的服务器了。我现在又可以直接从我的办公室电脑登录任何服务器,对这些服务器做各种操作,比如日志检索什么的。就是说,我敲一个 ssh -p 9001 localhost ,就连接到一台防火墙后面的服务器,直接省略了登录 jumpbox 的那个步骤。
您如果很细心,大概会想到,我说的局面是所有服务器都被禁止访问,而我上面这个隧道,只指定了一个目标服务器,就是 banned.com,那如果要访问多个服务器怎么办?比如,如果有10台服务器,提供的是同样的服务,那么如果从客户那里看到故障,故障可能会发生在任何一台服务器里。逐个去连接查看日志当然也可以,但是我喜欢用一行FOR循环语句,一次检索所有服务器的日志。这个能做到吗?
也可以的。ssh tunnel 允许同时开通多个隧道,语法很简单:
ssh -L [端口1]:[禁访服务器1]:22 -L [端口2]:[禁访服务器2]:22 中转电脑
就是说,中间那句指定隧道目的地的语句,-L [端口]:[禁访服务器],这个段落可以多次重复,每次用一个不同的端口号就可以了。比如:
ssh -L 9001:banned1.com:22 -L 9002:banned2.com:22 jumbox.com
这就开通了两个隧道,第一个,蓝色那段指定的那个,从端口9001出发,连接到 jumpbox,从这个隧道传给 jumpbox 的所有请求都会给转发到 banned1.com;另一个,红色指令指定的那个,从端口9002出发,还是连接到 jumpbox, 不过这个隧道过来的请求是给转发到 banned2.com。
这样,您如果要连接 banned1.com,就敲
ssh -p 9001 localhost
如果要连接 banned2.com,就敲
ssh -p 9002 localhost
如果需要开通10个隧道,就把 -L [端口]:[禁访服务器]:22 这个段落重复十遍,每次用一个不同的端口好就好了。
端口号当然不一定要从9001开始。那些协议保留端口不能用。除了那些,从1025到32768您都可以用。
用图形表示,这个隧道访问是这样走的:
敲 ssh -p 9001 localhost 可以远程连接那些被禁的电脑,在那些电脑内部穿梭操作。如果您需要做的不是连通那些电脑做现场操作,而只是想用 scp 从那里下载文件,那么这个 scp 指令应该怎么敲?
假设您要下载的文件是在 banned1.com,文件的路径是 /path/to/file。然后,您打算下载到本地电脑的这个路径:/home/tmp,那么,先建立隧道:
ssh -L 1234:banned1.com:22 [email protected]
(这次端口号用1234,就是强调一下从1024到32768都可以用)
隧道建立了,另外开一个 ssh 客户端,就可以这么敲 scp 指令:
scp -P 1234 user@localhost:/path/to/file /home/tmp
(注意这里的 -P 是要用大写的P。没办法,因为scp指令产生得早,当初作者编写 scp 的时候,小写的 p 已经用来指定别的用途了,后来要增加功能,支持钻隧道的操作,这个地方就只好用大写的 P。)
这行指令,连接的是 localhost(本地电脑),从字面上看,您会从本地电脑的 /path/to/ 下载 file,其实不是的。虽然说的是本地电脑,但是您的那个 “-P 1234”告诉 scp ,要连接到本地电脑的1234端口,然后,因为上面建立的隧道,scp 连接到1234端口之后,立刻被转接到了 banned1.com。所以,您实际上是从 banned1.com 的 /path/to 下载 file
您的主电脑不能随意访问防火墙后面的其他电脑。
但是,防火墙后面有一台电脑是允许您访问的,而且这台电脑上运行着 ssh,比如前面举例的家庭电脑或是 jumpbox。
这种情况下,您可以用 ssh -L 建立一个隧道,这个隧道连通了您的电脑和那个防火墙后面的可用电脑,就是说,这是一个穿越防火墙的隧道。有了这样的隧道,就可以从您自己的电脑上直接访问防火墙后面的其他的服务器了。
这么钻隧道,并没有违反公司的安全规定,因为,您并不是从围墙下面挖隧道,您是通过公司允许的中转站来建立隧道。就用我说的这个 jumpbox 做例子,您能借助这个 jumpbox 挖隧道,就说明您有进入这个 jumpbox 的密码。这个密码比里面服务器的密码安全级别还高。您既然能到这个地方来挖隧道,那本来就不是外人。所以这是允许使用的工作技巧。