1. 程式人生 > >SSH反向隧道進行內網穿透

SSH反向隧道進行內網穿透

對應的情況

這篇文章主要介紹瞭如何利用SSH 反向隧道穿透NAT,並演示瞭如何維持一條穩定的SSH 隧道。

假設有機器A 和B,A 有公網IP,B 位於NAT 之後並無可用的埠轉發,現在想由A 主動向B 發起SSH 連線。由於B 在NAT 後端,無可用公網IP + 埠 這樣一個組合,所以A 無法穿透NAT,這篇文章應對的就是這種情況。

首先有如下約定,因為很重要所以放在前面:

機器代號 機器位置 地址 賬戶 ssh/sshd 埠 是否需要執行sshd
A 位於公網 a.site usera 22
B 位於NAT之後 127.0.0.1 userb 22
C 位於NAT之後 127.0.0.1 userc 22

這裡預設你的系統init 程式為systemd,如果你使用其他的init 程式,如果沒有特殊理由還是換到一個現代化的GNU/Linux 系統吧……

SSH 反向隧道

這種手段實質上是由B 向A 主動地建立一個SSH 隧道,將A 的6766 埠轉發到B 的22 埠上,只要這條隧道不關閉,這個轉發就是有效的。有了這個埠轉發,只需要訪問A 的6766 埠反向連線B 即可。

首先在B 上建立一個SSH 隧道,將A 的6766 埠轉發到B 的22 埠上:

B:

 $ ssh -p 22 -qngfNTR 6766:127.0.0.1:22 [email protected]

然後在A 上利用6766 埠反向SSH 到B:

A:

$ ssh -p 6766 [email protected]

要做的事情其實就是這麼簡單。

隧道的維持

穩定性維持

然而不幸的是SSH 連線是會超時關閉的,如果連線關閉,隧道無法維持,那麼A 就無法利用反向隧道穿透B 所在的NAT 了,為此我們需要一種方案來提供一條穩定的SSH 反向隧道。

一個最簡單的方法就是autossh,這個軟體會在超時之後自動重新建立SSH 隧道,這樣就解決了隧道的穩定性問題,如果你使用Arch Linux,你可以這樣獲得它:

$ sudo pacman -S autossh

下面在B 上做之前類似的事情,不同的是該隧道會由autossh 來維持:
B:

$ autossh -p 22 -M 6777 -NR 6766:127.0.0.1:22 [email protected]

-M 引數指定的埠用來監聽隧道的狀態,與埠轉發無關。

之後你可以在A 上通過6766 埠訪問B 了:

A:

$ ssh -p 6766 [email protected]

隧道的自動建立

然而這又有了另外一個問題,如果B 重啟隧道就會消失。那麼需要有一種手段在B 每次啟動時使用autossh 來建立SSH 隧道。很自然的一個想法就是做成服務,之後會給出在systemd 下的一種解決方案。

“打洞”

之所以標題這麼起,是因為自己覺得這件事情有點類似於UDP 打洞,即通過一臺在公網的機器,讓兩臺分別位於各自NAT 之後的機器可以建立SSH 連線。

下面演示如何使用SSH 反向隧道,讓C 連線到B。

首先在A 上編輯sshd 的配置檔案/etc/ssh/sshd_config,將GatewayPorts 開關開啟:

GatewayPorts yes

然後重啟sshd:
A:

$ sudo systemctl restart sshd

然後在B 上對之前用到的autossh 指令略加修改:
B:

$ autossh -p 22 -M 6777 -NR '*:6766:127.0.0.1:22' [email protected]

之後在C 上利用A 的6766 埠SSH 連線到B:
C:

$ ssh -p 6766 [email protected]

至此你已經輕而易舉的穿透了兩層NAT。

最終的解決方案

整合一下前面提到的,最終的解決方案如下:

首先開啟A 上sshd 的GatewayPorts 開關,並重啟sshd(如有需要)。

然後在B 上新建一個使用者autossh,根據許可權最小化思想,B 上的autossh 服務將以autossh 使用者的身份執行,以盡大可能避免出現安全問題:
B:

 
  1. $ sudo useradd -m autosshB

  2. $ sudo passwd autossh

緊接著在B 上為autossh 使用者建立SSH 金鑰,並上傳到A:
B:

 
  1. $ su - autossh

  2. $ ssh-keygen -t 'rsa' -C '[email protected]'

  3. $ ssh-copy-id [email protected]

注意該金鑰不要設定密碼,也就是執行ssh-keygen 指令時儘管一路回車,不要輸入額外的字元。

然後在B 上建立以autossh 使用者許可權呼叫autossh 的service 檔案。將下面文字寫入到檔案/lib/systemd/system/autossh.service,並設定許可權為644:

 
  1. [Unit]Description=Auto SSH Tunnel

  2. After=network-online.target

  3. [Service]

  4. User=autossh

  5. Type=simple

  6. ExecStart=/bin/autossh -p 22 -M 6777 -NR '*:6766:127.0.0.1:22' [email protected] -i /home/autossh/.ssh/id_rsa

  7. ExecReload=/bin/kill -HUP $MAINPID

  8. KillMode=process

  9. Restart=always

  10. [Install]

  11. WantedBy=multi-user.target

  12. WantedBy=graphical.target

在B 上設定該服務自動啟動:
B:

$ sudo systemctl enable autossh

如果你願意,在這之後可以立刻啟動它:
B:

$ sudo systemctl start autossh

然後你可以在A 上使用這條反向隧道穿透B 所在的NAT SSH 連線到B:
A:

$ ssh -p 6766 [email protected]

或者是在C 上直接穿透兩層NAT SSH 連線到B:
C:

$ ssh -p 6766 [email protected]

如果你對SSH 足夠熟悉,你可以利用這條隧道做更多的事情,例如你可以在反向連線時指定動態埠轉發:
C:

$ ssh -p 6766 -qngfNTD 7677 [email protected]

假設C 是你家中的電腦,A 是你的VPS,B 是你公司的電腦。如果你這樣做了,那麼為瀏覽器設定埠為7677 的sock4 本地(127.0.0.1)代理後,你就可以在家裡的瀏覽器上看到公司內網的網頁。

轉自:https://blog.csdn.net/lidongshengajz/article/details/73482908