SSH 端口轉發 – 你不讓我看,我也能看
在之前 GRE 的文章中,我們知道隧道技術可以解決異種網絡的通信問題。在今天這篇文章中,將認識隧道技術的另一應用 – SSH 端口轉發。
首先我們對 SSH 並不陌生,是應該非常普遍的加密協議,用於在不安全的網絡中提供安全的傳輸環境,常見的用途是用於遠程登錄。而今天要介紹的端口轉發,原理類似。
端口轉發解決的問題:
- 增加安全性,加密 Client 到 Server 端的通信數據
- 突破防火牆限制,完成一些被禁止的 TCP 連接
端口轉發的類型
在此之前,我們先了解一下端口轉發的概念,端口轉發是 SSH 的一種應用,可以理解成在本地 SSH Client 和遠程 SSH Server 建立了一條安全的隧道,而這條隧道傳輸的內容可以是運行的其他 TCP 端口的流量。在隧道傳輸這些流量時,會進行加密,常見的 Telnet, SMTP, LDAP, HTTP 等等使用 TCP 作為傳輸層的協議都可以進行端口轉發。
通常來說,端口轉發分為三種類型,本地端口轉發,遠程端口轉發,動態不定端口轉發。會依次從應用場景和如何實現來介紹。
本地端口轉發
在給客戶部署應用時,通過來說訪問的都是客戶的內網環境,一般需要我們掛上客戶的 VPN 然後通過提供的跳板機來訪問目標服務器。但這樣的配置,就給在一些 debug 場景帶來很大的不便。
來看這樣一個場景:
這裡 Client A 需要依賴於 Server B 上一個 TCP 應用才能進行開發,但是由於防火牆的設置,Client A 的流量會被 Deny 掉。但提供了一台 Server A,而 Server A 到 Server B 卻是可達的。這時我們就可以利用端口轉發技術,通過 Server A 間接地實現和 Server B 的通信。這時 Server A 也就是常說的 Jump Server.
可以將 Client A 和 Server A 之間看成一條隧道,而隧道傳輸的內容就是 Server A 訪問 Server B 的流量。
下面來配置一下:
ssh -L <local port>:<remote host>:<remote port> <SSH hostname>
# local port 相當於 ssh client 端口
# remote host 是目標主機 Server B 的地址
# remote port 是目標主機 Server B 的端口
# ssh hostname 是跳板機,也就是 Server A 的地址
# 在 Client A 上
ssh -NfL 65001:10.124.207.152:8000 [email protected]
-f 表示後台運行
-N 表示不輸入命令
-L 表示本地端口轉發
需要注意的內容:
- Server A 到 Server B 一定是可達的
- 另外在綁定端口時,要選擇沒有被使用的端口
- 選用 1024-65535 之間的端口,之前的端口是給管理員使用的。
如何關閉:
like-unix: ps 找到進程 kill 掉
windows:
netstat -ano | findstr "65001"
taskkill /f /t /im 19036
遠程端口轉發
遠程端口轉發和本地端口轉發很像,只不過調換了 ssh server 和 ssh client 的位置。
考慮下面的場景,還是 Client A 無法訪問 Server B,但是 Server A 可以訪問 Server B, 與之前不同的是,Client A 也不能訪問 Server A 了,但 Server A 可以訪問 Client.
這時我們可以在 Server A 進行配置,把 Client A 作為 SSH Server 而自己作為 SSH Client 建立隧道。和之前本地一樣,在 Client A 上訪問配置的端口,就會把流量轉發給 SSH Client 也就是 SSH Server A,這時 Sever A 再將流量轉發至 Server B.
$ ssh -R <ssh client port>:<destnation host>:<destnation port> <ssh client host>
# Server B 進行配置
ssh -NfR 65001:10.124.207.152:8000 [email protected]
這時我們就可以達到和本地端口轉發相同的效果,在 Client A 上訪問 Server B.
如果分不清本地還是遠程端口轉發,可以通過 SSH Client 和 SSH server 來在加上訪問應用的順序加以區分
比如這裡 Client A 想要訪問 Server B 的 HTTP。
那麼 Client A 上的瀏覽器作為 HTTP 的客戶端,Server B 作為 HTTP 的服務端。也就是在 HTTP 應用視角,是從 Client A 給 Server B 發送請求。這個無論是本地還是遠程,方向都一樣。
接着再看 SSH 的客戶端和服務端。
如果 SSH 的客戶端在 Client A,則說明是本地端口轉發。和 HTTP client 和 server 同向。由於建立的轉發端口在本地,所以叫本地轉發。
否則如果是 SSH 的客戶端在 Server A,則說明是遠程端口轉發。和 HTTP client 和 server 反向。由於建立的轉發端口在遠端,所以叫遠程端口轉發。
其實無論是同向和反向,都是建立了一條隧道,只不過發起者不一樣,實現的目的都是一樣的。
本地和遠程端口轉發的共享
有時我們會希望共享 SSH Client 和 SSH Server 建立的隧道,提供給其他主機同時使用。這時我們可以通過 -g
參數來實現。
比如對本地端口轉發進行共享:
ssh -g -NfL 65001:10.124.207.152:8000 [email protected]
原來僅對 localhost 和 127.0.0.1 生效,現在對當前主機的所有地址都會生效,也就是 0.0.0.0 的範圍。在其他主機上可以通過訪問 SSH Client IP:65001 來進行服務的訪問。
遠程端口轉發同理:
ssh -g -NfR 65001:10.124.207.152:8000 [email protected]
動態端口轉發
動態端口轉發的原理和本地及遠程沒有任何的區別,唯一的不同是,對於本地和遠程來說我們需要固定訪問應用的端口號,比如 80,443 等等。
但假設應用的端口不固定或者需要很多的端口號怎麼辦?這時就需要動態端口轉發。
ssh -D <local port> <SSH Server>
# local port - ssh client 開啟的代理轉發端口
# ssh server - ssh server 的ip及端口
ssh -g -Nf -D 65001 [email protected]
可以用 curl 進行測試:
curl --socks5 127.0.0.1:6500 //10.124.207.152:8000/api-token-auth/
總結
最後我們完成了本地,遠程,共享,動態的端口轉發配置。
從整體來看,其實實現的都是相同的功能。在 SSH Client 和 SSH Server 中建立隧道。只不過有時隧道連接的方向是不同的。