SSH 端口轉發 - 你不讓我看,我也能看

在之前 GRE 的文章中,我們知道隧道技術可以解決異種網絡的通信問題。在今天這篇文章中,將認識隧道技術的另一應用 - SSH 端口轉發。

首先我們對 SSH 並不陌生,是非常普遍的加密協議,用於在不安全的網絡中提供安全的傳輸環境,常見的用途是用於遠程登錄。而今天要介紹的端口轉發,原理類似。

端口轉發解決的問題:

  1. 增加安全性,加密 Client 到 Server 端的通信數據
  2. 突破防火牆限制,完成一些被禁止的 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  http://10.124.207.152:8000/api-token-auth/

總結

最後我們完成了本地,遠程,共享,動態的端口轉發配置。

從整體來看,其實實現的都是相同的功能。在 SSH Client 和 SSH Server 中建立隧道。只不過有時隧道連接的方向是不同的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章