網路協議之:一定要大寫的SOCKS

flydean發表於2021-11-30

簡介

很久很久以前,人們還穿的是草鞋,草鞋雖然穿著舒服,但是不夠美觀。然後人們就發現,用動物的皮也可以做成鞋,於是出現了皮鞋。但是皮鞋穿著磨腳,於是人們又發明了socks,套在腳上,代替腳跟鞋子接觸,既提高了舒適感,也減少了磨損,簡直是一舉兩得的事情,非常完美。

在網路世界,也存在這樣的socks,為了和真實世界的socks進行區分,這裡我們使用大寫的SOCKS。

SOCKS就是我們今天要講解的網路代理協議。

SOCKS的故事

在講解SOCKS之前,我們回顧一下OSI網路七層協議。

OSI是Open System Interconnect的縮寫,意為開放式系統互聯。

而SOCKS也是一種網路協議,它的作用和socks一樣,用來代替客戶端和伺服器端進行連線,也就是代理協議。

SOCKS在OSI七層協議的第五層,也就是會話層中,它處於表現層和傳輸層的中間。從上圖可以看到SOCKS的底層就是TCP和UDP協議。

作為一個代理協議,SOCKS可以提供基於TCP和UDP的代理,相較於HTTP的代理而言,SOCKS的代理更加底層,所以應用場景也會更多。

通常來說,SOCKS的標準埠是1080。

SOCKS的歷史

每個協議都有自己的發展史,SOCKS也不例外,如果要把所有協議的發展史以故事的形式講述起來一定會很有意思,大家可以期待一下,說不定某天這樣的文章就出現了。

代理是網路中的一項基本功能,SOCKS代理最先是由美國MIPS科技公司的David Koblas設計的。MIPS公司以開發MIPS架構和基於該架構的一系列 RISC CPU 晶片而聞名。不過後面被一系列的收購,最終MIPS 架構被放棄了,轉而支援RISC-V架構。

MIPS在1992年被Silicon Graphics收購了,在那一年Koblas發表了關於SOCKS的論文,SOCKS一舉成名。

SOCKS最廣泛使用的協議版本是4和5。SOCKS4是NEC的Ying-Da Lee發明的。因為SOCKS 4中並沒有關於安全方面的約定,但是對於現在的網路來說,安全越來越重要,所以出現了SOCKS5,SOCKS5協議最初是一種使防火牆和其他安全產品更易於管理的安全協議。

SOCKS協議的具體內容

現在常用的SOCKS協議主要有SOCKS4、SOCKS4a和SOCKS5。本節將會詳細講訴他們的協議構成。

SOCKS4

先看一下SOCKS4的請求資料package長得什麼樣子的:

含義VERCMDDSTPORTDSTIPID
位元組個數1124可變

VER 佔用1個位元組,表示的是SOCKS協議的版本號,對於SOCKS4來說,這個值是0x04。

CMD 佔用1個位元組,表示的是要執行命令的程式碼,有兩個選擇,其中0x01 表示建立一個TCP/IP 流連線,0x02表示建立一個TCP/IP埠繫結。

DSTPORT 佔用2個位元組,表示目標埠號。

DESTIP 佔用4個位元組,表示的是IPv4地址。

ID 佔用位元組不定,表示的是使用者ID。

對於請求資料,相應的返回資料如下:

含義VNREPDSTPORTDSTIP
位元組個數1124

VN佔用1個位元組,表示是返回的訊息的版本。

REP佔用1個位元組,表示返回的code:

位元組含義
0x5A請求授權
0x5B請求拒絕或者請求失敗
0x5C因為請求不包含客戶端ID或者伺服器端無法連線客戶端而失敗
0x5D因為客戶端ID不匹配而失敗

DSTPORT佔用兩個位元組,表示目的地的埠,如果沒有繫結的話,則為空。

DSTIP佔用4個位元組,表示客戶端繫結的目的地的IP地址。

舉個例子,如果客戶端想使用SOCKS4從Fred連線到66.102.7.99:80,請求如下:

0x04 | 0x01 | 0x00 0x50 | 0x42 0x66 0x07 0x63 | 0x46 0x72 0x65 0x64 0x00

其中最後一個欄位是Fred的ASCII編碼。

如果伺服器端返回OK,則對應的響應如下:

0x00 | 0x5A | 0xXX 0xXX | 0xXX 0xXX 0xXX 0xXX

其中0xXX可以是任意值。

當連線建立完畢之後,所有的SOCKS客戶端到SOCKS伺服器端的請求都會轉發到66.102.7.99。

SOCKS4a

因為SOCKS4只能指定目的伺服器的IP地址,這對應伺服器有多個IP的情況下會有很嚴重的限制。所以SOCK4a對SOCK4進行了擴充套件,可以支援目標伺服器的域名。

SOCKS4a也是由SOCKS4的作者Ying-Da Lee,提出來的。我們看下SOCKS4a的請求格式:

含義VERCMDDSTPORTDSTIPIDDOMAIN
位元組個數1124可變variable

SOCKS4a是在SOCKS4的最後加入了domain。

DOMAIN表示的是要連線到的目標伺服器的域名。使用null (0x00)來結尾。對應的DSTIP的前三個位元組設定為NULL,最後一個位元組設定成一個非0的值。

服務端的響應和SOCKS4是一樣的。

SOCKS5

雖然SOCKS5是SOCKS的最新版本,但是SOCKS5和SOCKS4是不相容的。SOCKS5支援認證,並且提供了對IPv6和UDP的支援。其中UDP可以用來進行DNS lookups。它的互動流程如下所示:

  1. 客戶端和伺服器端進行連線,併傳送一個greeting訊息,同時包含了支援的認證方法列表。
  2. 伺服器端選擇一個支援的認證方法,如果都不支援,則傳送失敗響應。
  3. 根據選中的認證方法,客戶端和伺服器進行後續的認證互動,互動流程跟選中的認證方法相關。
  4. 客戶端以SOCKS4相似的方式傳送連線請求。
  5. 伺服器端傳送和SOCKS4相似的響應。

我們看下greeting訊息的格式:

含義VERNAUTHAUTH
位元組個數11可變位元組

VER 佔用1個位元組表示SOCKS的版本號,這裡是0x05。

NAUTH 佔用1個位元組,表示支援的認證方法的個數。

AUTH 是可變位元組,表示的是支援的認證方法。一個位元組表示一個方法,支援的方法如下:

    0x00: 沒有認證
    0x01: GSSAPI 
    0x02: 使用者名稱/密碼 (RFC 1929)
    0x03–0x7F: methods assigned by IANA
        0x03: Challenge-Handshake Authentication Protocol
        0x04: 未分配
        0x05: Challenge-Response Authentication Method
        0x06: Secure Sockets Layer
        0x07: NDS Authentication
        0x08: Multi-Authentication Framework
        0x09: JSON Parameter Block
        0x0A–0x7F: 未分配
    0x80–0xFE: 內部使用的保留方法

對應的伺服器端的響應如下:

含義VERCAUTH
位元組個數11

VER 佔用1個位元組,表示的是版本號。對於SOCKS5來說,它的值是0x05。

CAUTH 佔用1個位元組,表示選中的認證方法。如果沒有被選中,則設定為0xFF。

選好認證方法之後,接下來就是客戶端和伺服器端的認證互動了,這裡我們選擇最基本的使用者名稱和密碼0x02認證為例。

客戶端傳送認證請求:

含義VERIDLENIDPWLENPW
位元組個數11(1-255)1(1-255)

VER 佔用1個位元組表示當前使用者名稱和密碼認證的版本。

IDLEN 佔用1個位元組,表示使用者名稱的長度。

ID 佔用1到255個位元組,表示使用者名稱。

PWLEN 佔用1個位元組,表示密碼的長度。

PW 就是密碼。

對應的伺服器端的響應如下:

含義VERSTATUS
位元組個數11

VER 佔用1個位元組,表示版本號。

STATUS 佔用1個位元組,表示伺服器的響應狀態。

接下來,客戶端就可以和伺服器端傳送建立連線訊息了:

含義VERCMDRSVDSTADDRDSTPORT
位元組個數111可變位元組2

CMD 是連線可選的命令,0x01表示建立TCP/IP流連線,表示建立TCP/IP埠繫結,0x03表示連線一個UDP埠。

RSV 是保留位元組,必須是0x00。

DSTADDR是SOCKS5的地址。地址的定義是這樣的:

含義TYPEADDR
位元組個數1可變位元組

TYPE 表示地址的型別,0x01是IPv4地址,0x03是域名,0x04是IPv6地址。

ADDR 表示的是地址,如果是IPv4,則使用4個位元組,如果是域名,則第一個位元組表示長度,後面位元組表示域名。如果是IPv6地址,則使用16個位元組。

對應的伺服器端的響應如下:

含義VERSTATUSRSVBNDADDRBNDPORT
位元組個數111可變位元組2

總結

以上就是SOCKS4和SOCKS5的詳細協議內容。注意,SOCKS一定要大寫!

本文已收錄於 http://www.flydean.com/09-socks/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

相關文章