https://www.ramkitech.com/2012/04/how-to-do-ssh-tunneling-port-forwarding.html
https://www.cnblogs.com/popsuper1982/p/3875420.html
本文我將談到ssh是怎么工作的,到底什么是ssh tunneling隧道技術,ssh隧道到底有什么重要意義,以及如何搭建ssh tunnel.正常情況下,ssh server只要安裝了,那么默認情況下就允許ssh tunneling.
SSH tunneling(port forwarding)
tunneling是這樣一種概念:將一種網絡協議報文(這里更多指應用層協議)封裝到另外一個協議中傳輸,這里我們就是ssh,也就是說將其他協議的報文封裝到ssh中,由於ssh本身是加密的,因此所有的應用層網絡通信都是加密安全的. 在ssh tunneling的技術中,我們會綁定一個local port,並且所有targeted到這個local port的報文都將透明的加密並通過隧道轉發到remote system,正因為如此,SSH tunneling也被稱為端口轉發。
為什么需要ssh tunneling?
SSH雖然對於管理遠端系統是足夠了,但是ssh並不足以用於訪問所有遠端系統所提供的服務。
需要注意的是:在上面的3個系統中,ssh server daemon service都運行着並監聽22端口,而防火牆允許使用ssh client連接這個22端口.
在上面的網絡架構中101可以和PrivateServer 102直接通信,因為兩個系統都直接和internet相連接,但是101卻不能和intranet 10.10.1.11通信,因為從101系統的角度來說,10.10.1.11是一個non routeable的IP地址,該IP地址本身只是一個local ip,而不是公網的IP,因此無法路由dest addr是該私有網絡的報文.
現在的需求是我希望從101訪問到intranet 10.10.1.11的機器,怎么辦?
一個可行的方案是首先ssh登錄到privateserver(102機器)然后從102再ssh到intranet 10.10.1.11上.嗯,這是一個辦法,至少我們現在可以管理到10.10.1.11機器了,執行一些shell命令.但是問題是,如果10.101.1.11機器上也提供了其他的服務,比如VNC, apache web server, smtp, pop3, squid proxy等服務,我們如何從101機器上訪問這些服務呢,比如在101的機器上使用firefox來訪問10.10.1.11上的web server?僅僅使用ssh傳統的log/shell就無法滿足了。
真正的解決方案就是使用:ssh tunneling或者說ssh port forwarding
SSH是如何工作的?
在terminal中,當我們敲入ssh someone@private-server.org時,terminal application將調用ssh client,ssh client則連接到private-server.org機器的22端口(由ssh server監聽).然后client和server交換Identitiy,public key, cipher suite info並且在server端創建一個新的shell process.隨后client和server之間就建立了安全的通道了,這樣之后的所有command及response都通過這個secure channel來傳遞。
比如當ssh連接建立后,我將執行ls命令。那么ls命令將由ssh client加密封裝通過該通道發往server.server則解密取出命令'ls'並且在shell(該shell就是ssh鏈接創建時所創建的)中執行,所有的輸出將被redirect到該隧道的另一端-ssh client上,最后ssh client則解密取出output消息打印在terminal application上。
這里需要說明的是ssh本身只使用了22端口(也就是ssh server監聽的那個端口)
ssh tunneling
ssh協議本身要求對遠程機器上服務的訪問請求是通過channels來傳遞的。一個ssh connection可以包含多個channels,這有點類似於有線電視同軸電纜上可以同時傳輸多個信道的電視節目一樣。每一個channel則代表着單一的那個service.比如,你通過Net::ssh的方式激活了一個遠程主機上的一個進程時,就將創建一個channel專門用於服務於那個invocation,和那個process有關的所有的input和output都將經由那個channel來傳輸.而ssh connection本身則管理着該connection中所有已開的channels上流動的packets.這也意味着,雖然我們只有一個ssh connection,但是我們卻可以同時執行:運行新的進程,sftp下載文件,端口轉發port forwarding等。一個channel就是一個流
https://net-ssh.github.io/ssh/v1/chapter-3.html#s1
通常情況下我們就是用shell channel.但是在ssh tunneling模式下,我們准備使用data channel.需要了解的基礎概念是:在101機器上ssh client綁定了一個端口並且和server(102)建立了secure connection,並且創建一個data channel和一個shell channel(實際上我們可以通過-N選項來忽略shell channel的創建)。這樣,在101機器上任何應用如果發送數據到那個端口(就是ssh client綁定的那個端口),那么ssh client將透明地截取數據加密后轉發給server(應該是通過所謂shell channel,不確定).而在server上(102)則接收並且解密這個數據並且做本地調用(這塊隨后就將討論)
ssh tunneling types
ssh提供3種類型的隧道,
- Dynamic Tunneling(SOCKS proxy)
- Local Port Forwarding
- Remote Port Forwarding
Dynamic Tunneling(Socks proxy)
ssh -D 8080 ramki@192.168.56.102
這里-D 8080可以解讀為SOCKS V5 Proxy代理將在client side上綁定8080端口.
使用Dynamic Tunneling可以解決 Websense blocks your intended sites: websense是一個局域網代理解決方案
現在101的ssh client將在client side創建an一個SOCKS proxy server並且綁定一個local port 8080.隨后使用ramki這個用戶的信息去登錄遠程102服務器並且建立secure channel.
隨后client application比如firefox,chrome需要配置proxy使用SOCKS proxy server localhost:8080.然后在我們101機器的firefox地址欄輸入http://localhost,盡管在我們的101機器上並沒有任何web服務開啟着,我們卻可以看到來自server 102返回的web頁面!!!(注意:在102機器和10.10.1.11上都有apache綁定在其80端口上提供服務,而101機器並無web服務運行)
這到底發生了什么?
由於我們配置了proxy在瀏覽器中,因此瀏覽器將所有的http請求(甚至是localhost本身的http請求)都會送往8080端口,而SOCKS proxy正在這里監聽着8080端口,隨后SOCKS proxy將會把我們的http request打包並且送給ssh client加密后送往server.在server端則解密並且extract出來http request。這樣在server端,http request中的http://localhost/實際上上指向的是server機器本身,並且是80端口(因為http協議中如果不明確指明端口則意味着默認80端口)。因此server將invoke這個request,而我們的102機器中apache正好在監聽這個80端口並且提供服務,因此返回頁面內容並通過相同的secure channel返回到client side的應用(firefox)
還有一點需要說一下,本來從client機器101上,10.10.1.11是不可路由的,但是現在如果在101機器firefox瀏覽器上輸入http://10.10.1.11則可以正確訪問到10.10.1.11這個機器上部署的apache服務!!原因是該請求實際上是由102這台ssh server代為請求的,而102是可以訪問該10.10.1.11機器的哦!
優勢: 只要使用client機器上創建的proxy server就能夠訪問remote machine以及其身后子網機器上的任何服務;
缺點:我們需要在client application上配置這個proxy,但是如果應用本身並不支持proxy的配置選項,則我們仍然無法通過這種方式來訪問到對應的service。
可以參考以下博客文章搭建自己的proxy server:
https://bugthinking.com/bypass-internet-censorship-using-aws-and-shadowsocks/
驗證可用:
隨后必須使用firefox使能socks proxy,並且使用remote dns
local port forwarding
ssh -L 8000:localhost:80 ramki@192.168.56.102
注意這里的語法是: -L <local port> : <remote hostname> : <remote service port> user@sshserver
以上命令執行后,將在client side綁定了8000本地端口。任何發往8000端口的traffic將被redirect到ssh client(因為ssh client監聽綁定了8000端口),隨后加密送往server端,隨后server將直接deliver數據到localhost的80端口.在Dynamic tunnel(SOCKS)模式下,server會檢查packet並且決定我們要將該packet最終發往何處(比如,http://localhost則送往80, smtp則送往25)但是在local port forwarding模式下,目的地永遠是在建立這個local port forwarding命令中指定的remote service port! <remote hostname> : <remote service port>
這種模式下,101機器的firefox中不再需要配置proxy選項(如果有的話,你需要清除掉proxy配置),隨后在地址欄輸入 http://localhost:8000,那么http request將會送往local port 8000,隨后redirect並送往server.server則直接將報文送往server 102機器的port 80(注意這里的host及port是由 <remote hostname> : <remote service port>決定的,也就是localhost=102,80為目標端口)
如果你希望訪問10.10.1.11上的http service則必須創建一個新的local port forwarding,也就是說local port forwarding是點對點一對一的!我們不能使用前面已經創建好的隧道,因為老的隧道總是指向localhost:80,也就是102這台機器的80端口!
使用以下命令:
ssh -L 8000:10.10.1.11:80 ramki@192.168.56.102
以上命令執行后,則101 localhost的8000端口將再被重定向到10.10.1.11:80這個機器,via(通由)192.168.56.102
在firefox中,我們輸入http://localhost:8000,那么我們就將訪問到10.10.1.11的http service
好處: 不必配置proxy
缺點: 對於每個service我們都需要配置一個不同的Local port forwarding(即:對於192.168.56.102和10.10.1.11兩台機器上的http service,我們需要分別創建兩個local port轉發隧道)
下面是自己做實驗驗證的結果截圖
Remote Port Forwarding
remote port forwarding和local port forwarding是類似的,但是區別在於,我們將在server端創建port forwarding(102機器),而不是在101 ssh client side上
ssh -R 8000:localhost:80 ramki@192.168.56.101
這里非常重要的區別是:我們將從server連接到client,因此這里是ramki@192.168.56.101注意是101而不是102.(值得懷疑)當執行這條命令后將會連接到client並且在client side創建8000端口.
隨后client使用本地8000端口來連接server,就像是local port forwarding一樣.
為何remote port forwarding是重要的?
一般來說,計算機會在NAT之后,因此從外部是無法訪問到計算機的.
windows上使用實例
在windows機器上,如果希望運行ssh server,則有很多選擇,比如winsshd,freesshd,openssh等。如果只使用ssh client,則可以使用putty.
假設192.168.56.101機器上運行這windows系統,我們來演示如何使用ssh tunneling.打開putty並且輸入host ramki@192.168.56.102並選擇connection->ssh->tunnels,輸入8080到source port並選擇Dynamic,這就相當於啟動了sock proxy等價於-D 8080命令
如果希望使用local port forwarding則任意選擇一個未使用的port 6000到source port並且在destination中輸入localhost:80選擇local模式,等價於-L 6000:localhost:80
如果你希望訪問10.10.1.11機器的遠程桌面vnc,那么就創建一個local port forwarding,並且選擇destination是10.10.1.11:5900,因為5900端口是11這台機器的vnc server監聽的端口。隨后使用任何vnc client,比如我們使用tightvnc client連接到local port 6000