代理、ssh隧道那些事
文章目錄
一、各種代理術語介紹
在工作中,我們會和各種各樣的代理打交道,比如利用nginx做請求轉發、用shadowsocks翻牆,一些抓包軟包也用了代理。之前雖然知道代理的意思,但是對涉及代理各個專業術語並沒有很清晰的認識,今天就專門整理一下這些知識。
正向代理
比如由於牆的原因,我們大陸使用者訪問不了谷歌,這時我們就可以設定代理,通過把請求發向代理伺服器,讓代理伺服器來幫我們獲取資料並返回給我們。這種方式就是正向代理。在正向代理中,我們的目的是要訪問谷歌,但是需要通過代理伺服器來訪問。shadowsocks就是一個很好的例子。
反向代理
和正向代理不同,使用者訪問代理時甚至不知道自己訪問的是一個代理,使用者直接把這個代理的地址當成一個服務訪問,但是這個服務在接收使用者的請求會將請求轉發到其他的服務上獲取響應,然後再返回給使用者。比如nginx,我們訪問nginx暴露的一個埠,但是並不會知道nginx把請求轉發到了哪裡,我們也不關心這個,只要nginx能把我們想要的資料返回給我們就可以了,這就是反向代理。
透明代理
透明代理和正向代理比較像,也是通過代理去訪問某個服務。但是,和正向代理不同的是,使用者不需要去專門設定代理。典型的例子就是作業系統的防火牆,防火牆會攔截所有用的請求然後判斷哪些需要攔截,哪些直接放行。也就是說,使用者的請求是先經過防火牆然後再到達目標伺服器,這時候防火牆就可以理解為是一個透明代理。對於使用者來說,完全感知不到防火牆的存在,因為這個代理對使用者來說是透明的。
二、ssh隧道
對於ssh,我們平常都用來連線伺服器,但是其實ssh的功能遠不止如此。利用ssh提供的隧道功能,我們可以實現各種各樣的代理功能。
ssh支援3種形式的隧道,下面介紹一下這三種隧道
1. -D 動態隧道
通過 -D 引數,我們可以實現一個簡單的代理伺服器。
命令格式:
ssh -D [bind_address:]port [email protected]伺服器ip
在平常,我們的電腦是無法訪問谷歌的,但是現在我們手上有一臺伺服器A可以訪問谷歌。現在我們就可以通過ssh -D
來讓伺服器A變成一個代理伺服器,從而讓我們的電腦可以訪問谷歌。
# 繫結本地的8080埠,後面發往8080埠的請求都會通過ssh隧道發給伺服器A,由伺服器Alain進行請求後再將響應返回給我們
ssh -D 127.0.0.1:8080 [email protected]伺服器A的ip
之後我們需要設定一下瀏覽器的代理,地址使用127.0.0.1:8080。之後瀏覽器的請求都會走向8080埠,到8080埠後,經過ssh隧道發向伺服器A,伺服器把這個請求發往目標伺服器,之後拿到響應內容後返回給我們。整個過程就是一個正向代理的過程。
ssh的這個功能和shadowsocks的工作流程基本一樣,但是筆者簡單測試了下,使用ssh隧道構建的代理伺服器無論是效能還是穩定性都遠不如shadowsocks。具體的原因筆者也沒有很深入的去研究,不過可能這就是ssh動態隧道很少被人使用的原因吧。
2. -L 本地隧道
本地隧道也叫正向隧道,通過本地隧道,我們可以讓目標伺服器將我們本地的埠轉發到具體其他地址的埠。
命令格式:
ssh -L [bind_address:]port:host:hostport [email protected]伺服器ip
假設我們現在有個內網伺服器A上有一個程序佔用8080埠,我們的電腦要訪問內網伺服器只能通過跳板機,也就是伺服器B來訪問。這時候我們要在本地訪問伺服器A上那個8080的程序要怎麼做呢?ssh就可以幫我們做到
# 監聽了本地的8888埠,所有發往8888埠的請求都會發給伺服器B,伺服器B再將請求發給 '伺服器A的ip:8080',之後拿到響應後返回
# 前面的127.0.0.1可以不填,不填的話預設就是繫結在127.0.0.1上面
ssh -L [127.0.0.1:]8888:伺服器A的ip:8080 [email protected]伺服器B的ip
執行了上面的命令後,我們就可以直接通過127.0.0.1:8888就可以訪問伺服器A上的那個8080的程序。本地隧道建立後,所有發往127.0.0.1:8888地址的請求都會通過隧道發給伺服器B,然後伺服器B幫我們把請求發給配置好的伺服器A的ip:8080
,之後拿到請求返回給我們。
為了更好的理解本地隧道的工作原理,我們再模擬一個場景。假設我們現在可以直接訪問伺服器A的網路,但是A的8080埠並不對外開放,我們只能通過ssh協議登陸伺服器。這時候應該怎麼配置ssh隧道來訪問8080埠呢?
# 那個'127.0.0.1:8080'配置的是伺服器A要轉發的地址,以伺服器A的角度來看,要訪問的就是127.0.0.1的8080埠
ssh -L [127.0.0.1:]8888:127.0.0.1:8080 [email protected]伺服器A的ip
看到上面的配置,如果不知道本地隧道的轉發原理的可能會比較懵。
前面的[127.0.0.1:]8888
配置了要監聽的地址埠。接著127.0.0.1:8080
我們可以理解為只是配置一個地址,來告訴遠端的伺服器等會要把請求發到哪個地址。我們現在是把伺服器A來當代理伺服器,也就是伺服器A接收到隧道傳過來的請求後,就直接把對應的配置127.0.0.1:8080
拿到,往這個地址轉發。因此,後面那個配的是目標伺服器要訪問的地址。
可以看出,本地隧道玩的是反向代理。
3. -R 遠端隧道 —— 內網穿透
遠端隧道,也可以稱為反向隧道。通過遠端隧道,我們可以實現內網穿透。
命令格式:
ssh -R [bind_address:]port:host:hostport [email protected]伺服器ip
# bind_address 表示遠端伺服器繫結的ip地址。不過經筆者測試,這個引數好像並沒有什麼用,無論填什麼都不會改變監聽地址
# port 遠端伺服器要監聽的埠
# host 要轉發的ip地址。後面會在本地去訪問這個ip
# hostport 要轉發的埠
由於ipv4資源的緊缺,我們上網分配到的ip一般都是內網ip,由於是內網ip,其他區域網以外的伺服器就沒辦法訪問到我們的電腦了。
如果我們在自己的電腦上部署了一個網站,想要其他人可以訪問到,就需要用到內網穿透的功能。用ssh的隧道加一個有公網ip的伺服器,我們就可以實現內網穿透。
假設我們本地部署了一個網站,佔用埠8080,手上有一個伺服器A,我們可以這麼配置:
# 在伺服器A上面監聽一個8888的埠,之後只要有人訪問埠8888,ssh將會將請求經過隧道傳送給我們的電腦上
# 之後我們的電腦就把請求發給配置好的地址 '127.0.0.1:8080'上,然後把響應內容返回給呼叫者。
ssh -R 8888:127.0.0.1:8080 [email protected]伺服器A
這個和本地隧道其實就是反過來的關係。訪問者把請求發到遠端伺服器,然後遠端伺服器把請求轉發到本地,本地通過配置好的地址去轉發請求,最後返回結果。也就是說,後面配置的’127.0.0.1:8080’是以本地電腦的身份去訪問的,所以可以實現內網穿透。
顯然,遠端隧道也是屬於反向代理的一種。
使用遠端隧道時要注意,一般雲伺服器上的ssh服務預設是禁止做遠端隧道轉發的。當我們執行上訴命令時,它會只繫結自己的迴環ip 127.0.0.1,這樣外部的訪問就無法訪問到我們繫結的埠了,就不能達到內網穿透的功能了。
通過編輯sshd的配置檔案我們可以將ip繫結到0.0.0.0上,使所有人都可以訪問這個埠。
vim /etc/ssh/sshd_config # 將對應的配置項 GatewayPorts 的值修改成 yes GatewayPorts yes
4. ssh的一些其他技巧
既然說到ssh了,這裡再介紹一些ssh的使用姿勢。
在我們使用-R、-D、-L這些引數打隧道的同時,會登入到遠端伺服器,退出伺服器則會關閉這個隧道。如果我們只是想打隧道而不打算登入伺服器的話,命令我們可以這麼寫:
# -A 開啟認證代理連線轉發功能
# -C 表示對所有的輸入輸出都壓縮,使用的是gzip壓縮
# -N 表示不執行遠端指令
# -f 表示後臺執行ssh指令,一般 Nf 一起使用就可以不登入遠端伺服器了
# -L 表示建立本地隧道
ssh -A -CNfL 8888:127.0.0.1:8080 [email protected]目標伺服器
上面的命令執行後將會在後臺執行,而不會登陸上伺服器。我們可以通過ps -ef|grep ssh
命令找到對應的程序id。不過ssh也會有超時時間,超過一定時間ssh隧道也會自動斷掉。
登陸內網機器時,無需通過跳板機登陸
我們登陸公司的伺服器時,經常需要先登陸跳板機後才能登陸指定的伺服器,這樣操作起來就很麻煩。其實通過設定ssh的代理,我們可以直接一個命令登陸上目標伺服器。
在使用者目錄的.ssh
下新建一個配置檔案config
,如果有則不用建立。
在配置檔案最後新增以下內容:
# 如果你的私鑰需要密碼,配置上這個就不用一直輸入密碼了
AddKeysToAgent yes
# 定義跳板機的相關資訊
host jump
user kongtrio
port 指定ssh到跳板機的埠
hostname 跳板機ip
#forwardagent yes
identityfile ~/.ssh/id_rsa
# 定義之後要輸入的命令格式
host *.jump
user yjb1
port 跳板機要去連你的目標伺服器的埠
proxycommand ssh -W $(echo %h | sed -e "s/.jump$//"):%p jump
# 下面這個配置保證長時間不操作終端時,不會和伺服器斷開
ServerAliveInterval 60
配置好上面的config檔案之後,只要輸入命令ssh 192.168.0.1.jump
就可以登入上我們的伺服器了。原理大概就是ssh匹配到host是以’.jump’結尾了,就使用配置的proxycommand進行連線。之後通過跳板機做代理直接連線上目標伺服器。
不僅登陸不用通過跳板機,傳輸檔案也不用經過跳板機了:
# 一個命令就能傳輸檔案了,不用再scp到跳板機,然後再去跳板機scp到目標機器
scp file 192.168.0.1.gw:/home/user/