之前編寫的一個基於openfire伺服器的即時通訊軟體,因為部署環境需要,需要增加代理登入通訊的實現。整理了一下相關代理的知識分享一下。
一個基於TCP協議的客戶端希望與一個只能通過特定網路節點才可以聯通的目標建立通訊時,它必須在該節點搭建代理,先建立一個與SOCKS伺服器上埠的TCP連線(TCP埠可以是1080)。當連線建立後,客戶端和代理伺服器進入協議的“握手(negotiation)”過程,握手通過過後,這時就建立了客戶端和代理之間的連線。完成握手後代理可以看作一個透明的網路,向代理髮送真正的請求協議即可實現代理請求。
整個代理過程主要分兩個重要的階段“協議握手”、“代理請求”,代理請求由代理伺服器上的代理服務處理,現在有很多成熟的代理軟體,選一個即可。我們主要實現的是基於代理軟體的連線,或者說是實現基於SOCKS V5協議的連線過程(應用是代理IM的通訊),所以主要實踐“協議握手(negotiation)”。
協議握手的過程:
- 連線代理伺服器.
- 傳送請求商定版本和認證方式。
- 請求認證。
客戶端連到伺服器後,然後就傳送請求來協商版本和認證方法〔格式見下〕:
VER |
NMETHODS |
METHODS |
1 |
1 |
1 to 255 |
SOCKS v5協議中,VER欄位被設定成X'05'。NMETHODS欄位包含了在METHODS欄位中出現的方法標示的數目(以位元組為單位)。 我們傳送請求商定版本和認證方式後(傳送05 01 00),伺服器從給定的方法中選擇一個併傳送一個方法選中的訊息回客戶端〔格式見下〕
VER |
METHOD |
1 |
1 |
返回的訊息中如果是X’FF’,這表示客戶端所列出的方法列表中沒有一個方法被選中,客戶端必須關閉連線。我們需要關注的第二位的訊息內容,返回的訊息是05 00或者05 02(00 忽略驗證 ;02 進行使用者驗證)。
下面我們要了解的則是“0x02 使用者名稱/密碼”驗證的過程。
當客戶端傳送帶有0x02認證方法的報文(如:“0x05 0x01 0x02”)到服務端時,根據報文,服務端得知客戶端支援使用者名稱/密碼認證(0x02),因此如果服務端需要驗證,則傳送“0x05 0x02”應答,這樣客戶端將會進入“使用者名稱/密碼”驗證過程。
“0x02 使用者名稱/密碼”驗證協議的報文格式是:
0x01 | 使用者名稱長度(1位元組)| 使用者名稱(長度根據使用者名稱長度域指定) | 口令長度(1位元組) | 口令(長度由口令長度域指定)
所以報文的長度是根據使用者名稱與密碼的長度而定,比如以下報文:
0x01 0x02 0x41 0x42 0x02 0x43 0x43
則表示傳送使用者名稱為“AB”密碼為“CC”的驗證報文。
服務端接收到使用者名稱/密碼驗證報文後進行相應處理並返回以下格式的應答報文:
0x01 | 驗證結果標誌
驗證過程結束後,客戶端就傳送詳細的請求資訊。如果協商的方法中有以完整性檢查和/或安全性為目的的封裝,這些請求必須按照該方法所定義的方式進行封裝。
協議握手完成之後,就需要傳送一個請求連線,這個連線即是對遠端伺服器的連線,因為現在我們直連的是代理伺服器,所以需要告訴代理伺服器,我們要連線xxx地址。
請求的格式如下:
VER |
CMD |
RSV |
ATYP |
DST.ADDR |
DST.PROT |
1 |
1 |
X’00’ |
1 |
Variable |
2 |
注:
· VER 協議版本: X’05’
· CMD
· CONNECT:X’01’
· BIND:X’02’
· UDP ASSOCIATE:X’03’
· RSV 保留
· ATYP 後面的地址型別
· IPV4:X’01’
· 域名:X’03’
· IPV6:X’04’'
· DST.ADDR 目的地址
· DST.PORT 以網路位元組順序出現的埠號
ATYP欄位中描述了地址欄位(DST.ADDR,BND.ADDR)所包含的地址型別:
X'01':基於IPV4的IP地址,4個位元組長;
X'03':基於域名的地址,地址欄位中的第一位元組是以位元組為單位的該域名的長度,沒有結尾的NUL位元組;·
X'04':基於IPV6的IP地址,16個位元組長。
Variable:表示該域的長度是可變的。
代理伺服器這邊會根據請求內容返回特定格式的訊息(如下格式)。
VER |
REP |
RSV |
ATYP |
BND.ADDR |
BND.PORT |
1 |
1 |
X’00’ |
1 |
Variable |
2 |
注:標識為RSV的欄位必須設為X’00’。
VER 協議版本: X’05’
REP 應答欄位:
X’00’ 成功
X’01’ 普通的SOCKS伺服器請求失敗
X’02’ 現有的規則不允許的連線
X’03’ 網路不可達
X’04’ 主機不可達
X’05’ 連線被拒
X’06’ TTL超時
X’07’ 不支援的命令
X’08’ 不支援的地址型別
X’09’ – X’FF’ 未定義
RSV 保留
ATYP 後面的地址型別
IPV4:X’01’
域名:X’03’
IPV6:X’04’
BND.ADDR 伺服器繫結的地址
BND.PORT 以網路位元組順序表示的伺服器繫結的段口
返回的資訊裡面都看到,返回結果在第二個域,為0則表示成功。
驗證請求成功後,Socket5整個TCP客戶端的連線就完成了。這時候代理伺服器就可以看作是一個透明的網路連線。