SSH隧道與端口轉(zhuǎn)發(fā)及內(nèi)網(wǎng)穿透
大家都知道SSH是一種安全的傳輸協(xié)議,用在連接服務(wù)器上比較多。不過(guò)其實(shí)除了這個(gè)功能,它的隧道轉(zhuǎn)發(fā)功能更是吸引人。下面是個(gè)人根據(jù)自己的需求以及在網(wǎng)上查找的資料配合自己的實(shí)際操作所得到的一些心得。
SSH/plink命令的基本資料:
ssh -C -f -N -g -L listen_port:DST_Host:DST_port user@Tunnel_Host
ssh -C -f -N -g -R listen_port:DST_Host:DST_port user@Tunnel_Host
ssh -C -f -N -g -D listen_port user@Tunnel_Host
相關(guān)參數(shù)的解釋:
-f Fork into background after authentication.
后臺(tái)認(rèn)證用戶/密碼,通常和-N連用,不用登錄到遠(yuǎn)程主機(jī)。
-L port:host:hostport
將本地機(jī)(客戶機(jī))的某個(gè)端口轉(zhuǎn)發(fā)到遠(yuǎn)端指定機(jī)器的指定端口. 工作原理是這樣的, 本地機(jī)器上分配了一個(gè) socket 偵聽(tīng) port 端口, 一旦這個(gè)端口上有了連接, 該連接就經(jīng)過(guò)安全通道轉(zhuǎn)發(fā)出去, 同時(shí)遠(yuǎn)程主機(jī)和 host 的 hostport 端口建立連接. 可以在配置文件中指定端口的轉(zhuǎn)發(fā). 只有 root 才能轉(zhuǎn)發(fā)特權(quán)端口. IPv6 地址用另一種格式說(shuō)明: port/host/hostport
-R port:host:hostport
將遠(yuǎn)程主機(jī)(服務(wù)器)的某個(gè)端口轉(zhuǎn)發(fā)到本地端指定機(jī)器的指定端口. 工作原理是這樣的, 遠(yuǎn)程主機(jī)上分配了一個(gè) socket 偵聽(tīng) port 端口, 一旦這個(gè)端口上有了連接, 該連接就經(jīng)過(guò)安全通道轉(zhuǎn)向出去, 同時(shí)本地主機(jī)和 host 的 hostport 端口建立連接. 可以在配置文件中指定端口的轉(zhuǎn)發(fā). 只有用 root 登錄遠(yuǎn)程主機(jī)才能轉(zhuǎn)發(fā)特權(quán)端口. IPv6 地址用另一種格式說(shuō)明: port/host/hostport
-D port
指定一個(gè)本地機(jī)器 “動(dòng)態(tài)的’’ 應(yīng)用程序端口轉(zhuǎn)發(fā). 工作原理是這樣的, 本地機(jī)器上分配了一個(gè) socket 偵聽(tīng) port 端口, 一旦這個(gè)端口上有了連接, 該連接就經(jīng)過(guò)安全通道轉(zhuǎn)發(fā)出去, 根據(jù)應(yīng)用程序的協(xié)議可以判斷出遠(yuǎn)程主機(jī)將和哪里連接. 目前支持 SOCKS4 協(xié)議, 將充當(dāng) SOCKS4 服務(wù)器. 只有 root 才能轉(zhuǎn)發(fā)特權(quán)端口. 可以在配置文件中指定動(dòng)態(tài)端口的轉(zhuǎn)發(fā).
-C Enable compression.
壓縮數(shù)據(jù)傳輸。
-N Do not execute a shell or command.
不執(zhí)行腳本或命令,通常與-f連用。
-g Allow remote hosts to connect to forwarded ports.
在-L/-R/-D參數(shù)中,允許遠(yuǎn)程主機(jī)連接到建立的轉(zhuǎn)發(fā)的端口,如果不加這個(gè)參數(shù),只允許本地主機(jī)建立連接。注:這個(gè)參數(shù)我在實(shí)踐中似乎始終不起作用。
建立本地SSH隧道例子
在我們計(jì)劃建立一個(gè)本地SSH隧道之前,我們必須清楚下面這些數(shù)據(jù):
1.中間服務(wù)器d的IP地址
2.要訪問(wèn)服務(wù)器c的IP地址
3.要訪問(wèn)服務(wù)器c的端口
現(xiàn)在,我們把上面這張圖變得具體一些,給這些機(jī)器加上IP地址。并且根據(jù)下面這張圖列出我們的計(jì)劃:
1.需要訪問(wèn)234.234.234.234的FTP服務(wù),也就是端口21
2.中間服務(wù)器是123.123.123.123
現(xiàn)在我們使用下面這條命令來(lái)達(dá)成我們的目的
1.ssh -N -f -L 2121:234.234.234.234:21 123.123.123.123
2.ftp localhost:2121 # 現(xiàn)在訪問(wèn)本地2121端口,就能連接234.234.234.234的21端口了
這里我們用到了SSH客戶端的三個(gè)參數(shù),下面我們一一做出解釋:
·-N告訴SSH客戶端,這個(gè)連接不需要執(zhí)行任何命令。僅僅做端口轉(zhuǎn)發(fā)
·-f告訴SSH客戶端在后臺(tái)運(yùn)行
·-L做本地映射端口,被冒號(hào)分割的三個(gè)部分含義分別是
·需要使用的本地端口號(hào)
·需要訪問(wèn)的目標(biāo)機(jī)器IP地址(IP:234.234.234.234)
·需要訪問(wèn)的目標(biāo)機(jī)器端口(端口:21)
·最后一個(gè)參數(shù)是我們用來(lái)建立隧道的中間機(jī)器的IP地址(IP: 123.123.123.123)
我們?cè)僦貜?fù)一下-L參數(shù)的行為。-L X:Y:Z的含義是,將IP為Y的機(jī)器的Z端口通過(guò)中間服務(wù)器映射到本地機(jī)器的X端口。
在這條命令成功執(zhí)行之后,我們已經(jīng)具有繞過(guò)公司防火墻的能力,并且成功訪問(wèn)到了我們喜歡的一個(gè)FTP服務(wù)器了。
如何建立遠(yuǎn)程SSH隧道
通過(guò)建立本地SSH隧道,我們成功地繞過(guò)防火墻開(kāi)始下載FTP上的資源了。那么當(dāng)我們?cè)诩依锏臅r(shí)候想要察看下載進(jìn)度怎么辦呢?大多數(shù)公司的網(wǎng)絡(luò)是通過(guò)路由器接入互聯(lián)網(wǎng)的,公司內(nèi)部的機(jī)器不會(huì)直接與互聯(lián)網(wǎng)連接,也就是不能通過(guò)互聯(lián)網(wǎng)直接訪問(wèn)。通過(guò)線路D-B-A訪問(wèn)公司里的機(jī)器a便是不可能的。也許你已經(jīng)注意到了,雖然D-B-A這個(gè)方向的連接不通,但是A-B-D這個(gè)方向的連接是沒(méi)有問(wèn)題的。那么,我們能否利用一條已經(jīng)連接好的A-B-D方向的連接來(lái)完成D-B-A方向的訪問(wèn)呢?答案是肯定的,這就是遠(yuǎn)程SSH隧道的用途。
與本地SSH一樣,我們?cè)诮⑦h(yuǎn)程SSH隧道之前要清楚下面幾個(gè)參數(shù):
·需要訪問(wèn)內(nèi)部機(jī)器的遠(yuǎn)程機(jī)器的IP地址(這里是123.123.123.123)
·需要讓遠(yuǎn)程機(jī)器能訪問(wèn)的內(nèi)部機(jī)器的IP地址(這里因?yàn)槭窍氚驯緳C(jī)映射出去,因此IP是127.0.0.1)
·需要讓遠(yuǎn)程機(jī)器能訪問(wèn)的內(nèi)部機(jī)器的端口號(hào)(端口:22)
在清楚了上面的參數(shù)后,我們使用下面的命令來(lái)建立一個(gè)遠(yuǎn)程SSH隧道
1.ssh -N -f -R 2222:127.0.0.1:22 123.123.123.123
現(xiàn)在,在IP是123.123.123.123的機(jī)器上我們用下面的命令就可以登陸公司的IP是192.168.0.100的機(jī)器了。
1.ssh -p 2222 localhost
-N,-f 這兩個(gè)參數(shù)我們已經(jīng)在本地SSH隧道中介紹過(guò)了。我們現(xiàn)在重點(diǎn)說(shuō)說(shuō)參數(shù)-R。該參數(shù)的三個(gè)部分的含義分別是:
·遠(yuǎn)程機(jī)器使用的端口(2222)
·需要映射的內(nèi)部機(jī)器的IP地址(127.0.0.1)
·需要映射的內(nèi)部機(jī)器的端口(22)
例如:-R X:Y:Z 就是把我們內(nèi)部的Y機(jī)器的Z端口映射到遠(yuǎn)程機(jī)器的X端口上。
建立SSH隧道的幾個(gè)技巧
自動(dòng)重連
隧道可能因?yàn)槟承┰驍嚅_(kāi),例如:機(jī)器重啟,長(zhǎng)時(shí)間沒(méi)有數(shù)據(jù)通信而被路由器切斷等等。因此我們可以用程序控制隧道的重新連接,例如一個(gè)簡(jiǎn)單的循環(huán)或者使用 djb’s daemontools . 不管用哪種方法,重連時(shí)都應(yīng)避免因輸入密碼而卡死程序。關(guān)于如何安全的避免輸入密碼的方法,請(qǐng)參考我的 如何實(shí)現(xiàn)安全的免密碼ssh登錄 。這里請(qǐng)注意,如果通過(guò)其他程序控制隧道連接,應(yīng)當(dāng)避免將SSH客戶端放到后臺(tái)執(zhí)行,也就是去掉-f參數(shù)。
保持長(zhǎng)時(shí)間連接
有些路由器會(huì)把長(zhǎng)時(shí)間沒(méi)有通信的連接斷開(kāi)。SSH客戶端的TCPKeepAlive選項(xiàng)可以避免這個(gè)問(wèn)題的發(fā)生,默認(rèn)情況下它是被開(kāi)啟的。如果它被關(guān)閉了,可以在ssh的命令上加上-o TCPKeepAlive=yes來(lái)開(kāi)啟。
另一種方法是,去掉-N參數(shù),加入一個(gè)定期能產(chǎn)生輸出的命令。例如: top或者vmstat。下面給出一個(gè)這種方法的例子:
1.ssh -R 2222:localhost:22 123.123.123.123 "vmstat 30"
檢查隧道狀態(tài)
有些時(shí)候隧道會(huì)因?yàn)橐恍┰蛲ㄐ挪粫扯ㄋ?,例如:由于傳輸?shù)據(jù)量太大,被路由器帶入stalled狀態(tài)。這種時(shí)候,往往SSH客戶端并不退出,而是卡死在那里。一種應(yīng)對(duì)方法是,使用SSH客戶端的ServerAliveInterval和ServerAliveCountMax選項(xiàng)。 ServerAliveInterval會(huì)在隧道無(wú)通信后的一段設(shè)置好的時(shí)間后發(fā)送一個(gè)請(qǐng)求給服務(wù)器要求服務(wù)器響應(yīng)。如果服務(wù)器在 ServerAliveCountMax次請(qǐng)求后都沒(méi)能響應(yīng),那么SSH客戶端就自動(dòng)斷開(kāi)連接并退出,將控制權(quán)交給你的監(jiān)控程序。這兩個(gè)選項(xiàng)的設(shè)置方法分別是在ssh時(shí)加入-o ServerAliveInterval=n和-o ServerAliveCountMax=m。其中n, m可以自行定義。
如何將端口綁定到外部地址上
使用上面的方法,映射的端口只能綁定在127.0.0.1這個(gè)接口上。也就是說(shuō),只能被本機(jī)自己訪問(wèn)到。如何才能讓其他機(jī)器訪問(wèn)這個(gè)端口呢?我們可以把這個(gè)映射的端口綁定在0.0.0.0的接口上,方法是加上參數(shù)-b 0.0.0.0。同時(shí)還需要打開(kāi)SSH服務(wù)器端的一個(gè)選項(xiàng)-GatewayPorts。默認(rèn)情況下它應(yīng)當(dāng)是被打開(kāi)的。如果被關(guān)閉的話,可以在/etc /sshd_config中修改GatewayPorts no為GatewayPorts yes來(lái)打開(kāi)它。
通過(guò)SSH隧道建立SOCKS服務(wù)器
如果我們需要借助一臺(tái)中間服務(wù)器訪問(wèn)很多資源,一個(gè)個(gè)映射顯然不是高明的辦法(事實(shí)上,高明確實(shí)沒(méi)有用這個(gè)方法)。幸好,SSH客戶端為我們提供了通過(guò)SSH隧道建立SOCKS服務(wù)器的功能。
通過(guò)下面的命令我們可以建立一個(gè)通過(guò)123.123.123.123的SOCKS服務(wù)器。
1.ssh -N -f -D 1080 123.123.123 # 將端口綁定在127.0.0.1上
2.ssh -N -f -D 0.0.0.0:1080 123.123.123.123 # 將端口綁定在0.0.0.0上
通過(guò)SSH建立的SOCKS服務(wù)器使用的是SOCKS5協(xié)議,在為應(yīng)用程序設(shè)置SOCKS代理的時(shí)候要特別注意。