使用SSH反向隧道进行内网穿透
這篇文章主要介紹了如何利用SSH 反向隧道穿透NAT,并演示了如何維持一條穩定的SSH 隧道。
假設有機器A 和B,A 有公網IP,B 位于NAT 之后并無可用的端口轉發,現在想由A 主動向B 發起SSH 連接。由于B 在NAT 后端,無可用公網IP + 端口?這樣一個組合,所以A 無法穿透NAT,這篇文章應對的就是這種情況。
首先有如下約定,因為很重要所以放在前面:
| A | 位于公網 | a.site | usera | 22 | 是 |
| B | 位于NAT 之后 | localhost | userb | 22 | 是 |
| C | 位于NAT 之后 | localhost | userc | 22 | 否 |
這里默認你的系統init 程序為systemd,如果你使用其他的init 程序,如果沒有特殊理由還是換到一個現代化的GNU/Linux 系統吧……
SSH 反向隧道
這種手段實質上是由B 向A 主動地建立一個SSH 隧道,將A 的6766 端口轉發到B 的22 端口上,只要這條隧道不關閉,這個轉發就是有效的。有了這個端口轉發,只需要訪問A 的6766 端口反向連接B 即可。
首先在B?上建立一個SSH 隧道,將A 的6766 端口轉發到B 的22 端口上:
| 1 | B $ ssh -p 22 -qngfNTR 6766:localhost:22 usera@a.site |
然后在A?上利用6766 端口反向SSH 到B:
| 1 | A $ ssh -p 6766 userb@localhost |
要做的事情其實就是這么簡單。
隧道的維持
穩定性維持
然而不幸的是SSH 連接是會超時關閉的,如果連接關閉,隧道無法維持,那么A 就無法利用反向隧道穿透B 所在的NAT 了,為此我們需要一種方案來提供一條穩定的SSH 反向隧道。
一個最簡單的方法就是autossh,這個軟件會在超時之后自動重新建立SSH 隧道,這樣就解決了隧道的穩定性問題,如果你使用Arch Linux,你可以這樣獲得它:
| 1 | $ sudo pacman -S autossh |
下面在B?上做之前類似的事情,不同的是該隧道會由autossh?來維持:
| 1 | B $ autossh -p 22 -M 6777 -NR 6766:localhost:22 usera@a.site |
-M?參數指定的端口用來監聽隧道的狀態,與端口轉發無關。
之后你可以在A 上通過6766 端口訪問B 了:
| 1 | A $ ssh -p 6766 userb@localhost |
隧道的自動建立
然而這又有了另外一個問題,如果B 重啟隧道就會消失。那么需要有一種手段在B 每次啟動時使用autossh?來建立SSH 隧道。很自然的一個想法就是做成服務,之后會給出在systemd?下的一種解決方案。
“打洞”
之所以標題這么起,是因為自己覺得這件事情有點類似于UDP 打洞,即通過一臺在公網的機器,讓兩臺分別位于各自NAT 之后的機器可以建立SSH 連接。
下面演示如何使用SSH 反向隧道,讓C 連接到B。
首先在A?上編輯sshd?的配置文件/etc/ssh/sshd_config,將GatewayPorts?開關打開:
| 1 | GatewayPorts yes |
然后重啟sshd:
| 1 | A $ sudo systemctl restart sshd |
然后在B?上對之前用到的autossh?指令略加修改:
| 1 | B $ autossh -p 22 -M 6777 -NR '*:6766:localhost:22' usera@a.site |
之后在C?上利用A?的6766 端口SSH 連接到B:
| 1 | C $ ssh -p 6766 userb@a.site |
至此你已經輕而易舉的穿透了兩層NAT。
最終的解決方案
整合一下前面提到的,最終的解決方案如下:
首先打開A?上sshd?的GatewayPorts?開關,并重啟sshd(如有需要)。
然后在B?上新建一個用戶autossh,根據權限最小化思想,B 上的autossh?服務將以autossh?用戶的身份運行,以盡大可能避免出現安全問題:
| 12 | B $ sudo useradd -m autosshB $ sudo passwd autossh |
緊接著在B?上為autossh?用戶創建SSH 密鑰,并上傳到A:
| 123 | B $ su - autosshB $ ssh-keygen -t 'rsa' -C 'autossh@B'B $ ssh-copy-id usera@a.site |
注意該密鑰不要設置密碼,也就是運行ssh-keygen?指令時盡管一路回車,不要輸入額外的字符。
然后在B?上創建以autossh?用戶權限調用autossh?的service 文件。將下面文本寫入到文件/lib/systemd/system/autossh.service,并設置權限為644:
| 123456789101112131415 | [Unit]Description=Auto SSH TunnelAfter=network-online.target[Service]User=autosshType=simpleExecStart=/bin/autossh -p 22 -M 6777 -NR '*:6766:localhost:22' usera@a.site -i /home/autossh/.ssh/id_rsaExecReload=/bin/kill -HUP $MAINPIDKillMode=processRestart=always[Install]WantedBy=multi-user.targetWantedBy=graphical.target |
在B 上讓network-online.target?生效:
| 1 | B $ systemctl enable NetworkManager-wait-online |
如果你使用systemd-networkd,你需要啟用的服務則應當是systemd-networkd-wait-online?。
然后設置該服務自動啟動:
| 1 | B $ sudo systemctl enable autossh |
如果你愿意,在這之后可以立刻啟動它:
| 1 | B $ sudo systemctl start autossh |
然后你可以在A?上使用這條反向隧道穿透B 所在的NAT SSH 連接到B:
| 1 | A $ ssh -p 6766 userb@localhost |
或者是在C?上直接穿透兩層NAT SSH 連接到B:
| 1 | C $ ssh -p 6766 userb@a.site |
如果你對SSH 足夠熟悉,你可以利用這條隧道做更多的事情,例如你可以在反向連接時指定動態端口轉發:
| 1 | C $ ssh -p 6766 -qngfNTD 7677 userb@a.site |
假設C?是你家中的電腦,A?是你的VPS,B?是你公司的電腦。如果你這樣做了,那么為瀏覽器設置端口為7677?的sock4?本地(localhost)代理后,你就可以在家里的瀏覽器上看到公司內網的網頁。
本文標題:使用SSH反向隧道進行內網穿透
文章作者:I&ME
發布時間:2016-02-17, 18:09:57
最后更新:2016-12-02, 00:03:54
原始鏈接:https://arondight.github.io/2016/02/17/使用SSH反向隧道進行內網穿透/?
總結
以上是生活随笔為你收集整理的使用SSH反向隧道进行内网穿透的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tf13: 简单聊天机器人
- 下一篇: RUNNING JUPYTER NOTE