SSH隧道:端口轉發功能詳解


SSH系列文章
SSH基礎:SSH和SSH服務
SSH轉發代理:ssh-agent用法詳解
SSH隧道:端口轉發功能詳解


1.1 ssh安全隧道(一):本地端口轉發

如下圖,假如host3和host1、host2都同互相通信,但是host1和host2之間不能通信,如何從host1連接上host2?

對於實現ssh連接來說,實現方式很簡單,從host1 ssh到host3,再ssh到host2,也就是將host3作為跳板的方式。但是如果不是ssh,而是http的80端口呢?如何讓host1能訪問host2的80端口?

ssh支持本地端口轉發,語法格式為:

ssh -L [local_bind_addr:]local_port:remote:remote_port middle_host

以上圖為例,實現方式是在host1上執行:

[root@xuexi ~]# ssh -g -L 2222:host2:80 host3

其中"-L"選項表示本地端口轉發,其工作方式為:在本地指定一個由ssh監聽的轉發端口(2222),將遠程主機的端口(host2:80)映射為本地端口(2222),當有主機連接本地映射端口(2222)時,本地ssh就將此端口的數據包轉發給中間主機(host3),然后host3再與遠程主機的端口(host2:80)通信。

現在就可以通過訪問host1的2222端口來達到訪問host2:80的目的了。例如:

再來解釋下"-g"選項,指定該選項表示允許外界主機連接本地轉發端口(2222),如果不指定"-g",則host4將無法通過訪問host1:2222達到訪問host2:80的目的。甚至,host1自身也不能使用172.16.10.5:2222,而只能使用localhost:2222或127.0.0.1:2222這樣的方式達到訪問host2:80的目的,之所以如此,是因為本地轉發端口默認綁定在回環地址上。可以使用bind_addr來改變轉發端口的綁定地址,例如:

[root@xuexi ~]# ssh -L 172.16.10.5:2222:host2:80 host3

這樣,host1自身就能通過訪問172.16.10.5:2222的方式達到訪問host2:80的目的。

一般來說,使用轉發端口,都建議同時使用"-g"選項,否則將只有自身能訪問轉發端口。

再來分析下轉發端口通信的過程。

當host4發起172.16.10.5:2222的連接時(即步驟①),數據包的目標地址和端口為"172.16.10.5:2222"。由於host1上ssh已經監聽了2222端口,並且知道該端口映射自哪台主機哪個端口,所以將會把該數據包目標地址和端口替換為"172.16.10.3:80",並將此數據包通過轉發給host3。當host3收到該數據包時,發現是host1轉發過來請求訪問host2:80的數據包,所以host3將代為訪問host2的80端口。

所以,host1和host3之間的通信方式是SSH協議,這段連接是安全加密的,因此稱為"安全隧道",而host3和host2之間通信協議則是HTTP而不是ssh

現在再來考慮下,通過本地端口轉發的方式如何實現ssh跳板的功能呢?仍以上圖為例:

[root@xuexi ~]# ssh -g -L 22333:host2:22 host3]

這樣只需使用ssh連上host1的22333端口就等於連接了host2的22端口。

最后,關於端口轉發有一個需要注意的問題:ssh命令中帶有要執行的命令。考慮了下面的三條在host1上執行的命令的區別。

[root@xuexi ~]# ssh -g -L 22333:host2:22 host3
[root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "ifconfig"
[root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "sleep 10"

第一條命令開啟了本地端口轉發,且是以登錄到host3的方式開啟的,所以執行完該命令后,將跳到host3主機上,當退出host3時,端口轉發功能將被關閉。另外,host1上之所以要開啟端口轉發,目的是為了與host2進行通信,而不是跳到host3上,所以應該在ssh命令行上加上"-f"選項讓ssh在本機host1上以后台方式提供端口轉發功能,而不是跳到host3上來提供端口轉發功能。

第二條命令在開啟本地轉發的時候還指定了要在host3上執行"ifconfig"命令,但是ssh的工作機制是遠程命令執行完畢的那一刻,ssh關閉連接,所以此命令開啟的本地端口轉發功能有效期只有執行ifconfig命令的一瞬間。

第三條命令和第二條命令類似,只不過指定的是睡眠10秒命令,所以此命令開啟的本地轉發功能有效期只有10秒。

結合上面的分析,開啟端口轉發功能時,建議讓ssh以后台方式提供端口轉發功能,且明確指示不要執行任何ssh命令行上的遠程命令。即最佳開啟方式為:

[root@xuexi ~]# ssh -f -N -g -L 22333:host2:22 host3

1.2 ssh安全隧道(二):遠程端口轉發

ssh除了支持本地端口轉發,還支持遠程端口轉發。顧名思義,遠程端口轉發表示的是將遠程端口的數據轉發到本地。

如下圖:假如host3是內網主機,它能和host2互相通信,也能和host1通信,但反過來,host1不能和host3通信。這時要讓host1訪問host3或host2就沒辦法通過本地端口轉發了,因為要在host1上開啟本地端口轉發,必須要和host3通信請求建立隧道。

可以通過在host3上發起遠程端口轉發來實現,因為host3能和host1通信,host3可以請求在host1和host3之間建立隧道。

語法如下:

ssh -R [bind_addr:]remote1_port:host:port remote1

以上圖為例,實現方式是在host3上執行:

[root@xuexi ~]# ssh -R 22333:host2:80 host1

這表示host3請求host1上的sshd服務,在host1上建立一個套接字監聽22333端口,它是host2端口的映射,當有主機連接host1:22333時,此連接中的數據全部都通過host1和host3之間的安全隧道轉發給host3,再由host3向host2的80端口發起訪問。由於host3請求開啟的轉發端口是在遠程主機host1上的,所以稱為"遠程端口轉發"。

再考慮下面這條命令所開啟的遠程轉發端口,它是在host3上執行的。

[root@xuexi ~]# ssh -R 22333:host3:80 host1

該命令將自身的host3:80映射到host1:22333上,這也能讓host1和host2、host3通信,因為隧道是建立在host1:22333<-->host3:80上的。

但是,遠程端口轉發和本地端口轉發最大的一個區別是,遠程轉發端口是由host1上的sshd服務控制的,默認配置情況下,sshd服務只允許本地開啟的遠程轉發端口(22333)綁定在環回地址(127.0.0.1)上,即使顯式指定了bind_addr也無法覆蓋。例如:

[root@xuexi ~]# ssh -R *:22333:host2:80 host1 

[root@xuexi ~]# netstat -tnlp
Active Internet connections (only servers)
tcp   0   0 0.0.0.0:22        0.0.0.0:*   LISTEN  8405/sshd  
tcp   0   0 127.0.0.1:25      0.0.0.0:*   LISTEN  1422/master
tcp   0   0 127.0.0.1:22333   0.0.0.0:*   LISTEN  8407/sshd  
tcp   0   0 :::22             :::*        LISTEN  8405/sshd  
tcp   0   0 ::1:25            :::*        LISTEN  1422/master
tcp   0   0 ::1:22333         :::*        LISTEN  8407/sshd

要允許本地的遠程轉發端口綁定在非環回地址上,需要在host1的sshd配置文件中啟用"GatewayPorts"項,它的默認值為no。啟動該選項后,不給定bind_addrbind_addr設置為"*"都表示綁定在所有地址上。如下:

[root@xuexi ~]# ssh -g -R *:22333:host2:80 host1

[root@xuexi ~]# netstat -tnlp
Active Internet connections (only servers)
tcp   0  0 0.0.0.0:22      0.0.0.0:*   LISTEN  8466/sshd  
tcp   0  0 127.0.0.1:25    0.0.0.0:*   LISTEN  1422/master
tcp   0  0 0.0.0.0:22333   0.0.0.0:*   LISTEN  8468/sshd  
tcp   0  0 :::22           :::*        LISTEN  8466/sshd  
tcp   0  0 ::1:25          :::*        LISTEN  1422/master
tcp   0  0 :::22333        :::*        LISTEN  8468/sshd

和前面的本地轉發端口一樣,建議的幾個選項是:"-g"、"-f"、"-N"。即推薦的命令寫法是:

[root@xuexi ~]# ssh -fgN -R 22333:host2:80 host1

現在,就可以通過訪問host1:22333達到訪問host2:80的目的了。如下圖所示。

1.3 ssh安全隧道(三):動態端口轉發(SOCKS代理)

無論是本地端口轉發還是遠程端口轉發,都是將某固定主機及其端口映射到本地或遠程轉發端口上,例如將host2:80映射到host1:2222。也就是說,本地或遠程轉發端口和目標端口所代表的應用層協議是一對一的關系,2222端口必須對應的是http的80端口,使用瀏覽器向host1:2222端口發起http請求當然沒問題,但是使用ssh工具向host1:2222發起連接將會被拒絕,因為host2上http服務只能解析http請求,不能解析ssh連接請求。

ssh支持動態端口轉發,由ssh來判斷發起請求的工具使用的是什么應用層協議,然后根據判斷出的協議結果決定目標端口。
以下圖為例進行說明,host1處在辦公內網,能和host3互相通信,但它無法直接和互聯網和host2通信,而host3則可以和host2以及互聯網通信。

要讓host1訪問互聯網,又能和host2的22端口即ssh服務通信,顯然在host1上僅設置一個本地端口轉發是不夠的,雖然可以設置多個本地轉發端口分別映射不同的端口,但這顯然比較笨重和麻煩。使用動態端口轉發即可。

語法格式為:

ssh -D [bind_addr:]port remote 

以上圖為例,在host1上執行:

[root@xuexi ~]# ssh -Nfg -D 2222 host3

執行完上面的命令,host1將在本地開啟SOCKS4或SOCKS5服務來監聽2222端口。只要客戶端程序工具(隱含了使用的應用層協議類型)將其自身的代理設置為host1:2222,則該程序所有產生的數據都將轉發到host1:2222,再由host1:2222將數據通過隧道轉發給host3,最后由host3和互聯網或host2上對應客戶端工具的應用層協議的端口進行通信。

其實很簡單,假如host4使用IE瀏覽器作為客戶端工具,並將IE瀏覽器的代理設置為host1:2222,由於IE瀏覽器發起的請求使用的是http協議(此處不考慮其他可能的協議),那么IE瀏覽器產生的數據都轉發到host1:2222,再由host1:2222通過隧道轉發給host3,host3能聯網,所以host4就實現了聯網功能。如下圖設置:

再比如host4上的QQ客戶端也可以設置代理。這樣QQ產生的數據都將通過host1:2222轉發出去,host1:2222再將QQ的數據轉發到host3上,host3知道這些數據使用的協議是oicq,所以host3會去連接騰訊的QQ服務器(oicq服務對應的端口)。

ssh只支持socks4和socks5兩種代理,有些客戶端工具中需要明確指明代理類型。

和本地、遠程端口轉發一樣,建議的選項是:"-f"、"-N"和"-g"。

由於ssh動態端口轉發是ssh客戶端的功能,所以不使用ssh命令,使用SecurtCRT、putty等ssh客戶端工具都可以實現代理上網。例如,本地主機不能上網,但能和172.16.10.6的SSH服務通信,而172.16.10.6能上網,則可以在本地主機先使用SecurtCRT連接172.16.10.6,再在對應的會話選項上做如下設置,使得本地主機也能上網。(注意:我沒說可以翻牆啊,好公民不翻牆!!!)

然后,在本地主機查看下是否監聽了SecurtCRT中指定的8888動態轉發端口。

現在,本機所有數據包都通過SecurtCRT所連接的172.16.10.6流向外界。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM