Socks 協(xié)議是一種代理 (Proxy) 協(xié)議, 例如我們所熟知的 Shdowsocks 便是 Socks 協(xié)議的一個(gè)典型應(yīng)用程序, Socks 協(xié)議有多個(gè)版本, 目前最新的版本為 5, 其協(xié)議標(biāo)準(zhǔn)文檔為 RFC 1928, 本文討論 Socks 5 協(xié)議的設(shè)計(jì)
代理服務(wù)器
通常在組織內(nèi)部會(huì)有自己專(zhuān)用的網(wǎng)絡(luò), 該網(wǎng)絡(luò)與公共網(wǎng)絡(luò) (如 Internet) 是隔離的, 而代理服務(wù)器可以創(chuàng)建一個(gè)從內(nèi)網(wǎng)到外網(wǎng)的通道, 用于組織內(nèi)的主機(jī)與組織外的主機(jī)進(jìn)行通信, 同時(shí)組織管理者可以在代理服務(wù)器上配置相應(yīng)的權(quán)限管控和監(jiān)控, 以約束和審查組織內(nèi)外主機(jī)的通信行為, 這里, 代理服務(wù)器實(shí)際上相當(dāng)于一個(gè)應(yīng)用層網(wǎng)關(guān), 在 Socks 協(xié)議之前沒(méi)有一套通用的標(biāo)準(zhǔn)來(lái)約束組織內(nèi)主機(jī)與代理服務(wù)器的交互方式, 這需要工程師自行實(shí)現(xiàn)相應(yīng)的數(shù)據(jù)轉(zhuǎn)發(fā), 而且對(duì)于應(yīng)用層協(xié)議往往是不透明的 (例如可能需要根據(jù)實(shí)際需求實(shí)現(xiàn)多種應(yīng)用層協(xié)議的網(wǎng)關(guān), 如 HTTP 代理, FTP 代理, SSH 代理等等), Socks 5 協(xié)議工作在傳輸層 (Transport Layer) 與應(yīng)用層 (Application Layer) 的中間, 提供了一種對(duì)應(yīng)用層協(xié)議透明的代理服務(wù), 當(dāng)組織內(nèi)主機(jī)與代理服務(wù)器完成 Socks 握手之后, 應(yīng)用層對(duì)代理服務(wù)器是無(wú)感知的, 例如地址分別為 A, B 的分布在組織內(nèi)外的兩個(gè)進(jìn)程進(jìn)行 HTTP 通信, 其中 C 為代理服務(wù)器, 實(shí)際的數(shù)據(jù)鏈路為 A → C → B, 但在引入 Socks 協(xié)議之后, 從應(yīng)用層的視角來(lái)看, 整個(gè)通信過(guò)程仍然是 A → B 的模式
基于 TCP 的 Socks 5
Socks 5 協(xié)議是對(duì) Socks 4 的改進(jìn), 在 Socks 4 協(xié)議中, 對(duì)于傳輸層協(xié)議僅支持 TCP 協(xié)議, 并且 Socks 4 協(xié)議沒(méi)有安全性相關(guān)的設(shè)計(jì), Socks 5 協(xié)議增加了對(duì) UDP 的支持, 同時(shí)提供了安全加密認(rèn)證機(jī)制, Socks 5 協(xié)議的第一步是與代理服務(wù)器握手, 首先客戶(hù)端向代理服務(wù)器發(fā)起握手請(qǐng)求, 其數(shù)據(jù)包格式如下所示:
- VER 字段表征 Socks 協(xié)議版本, 占 1 字節(jié), 對(duì)于 Socks 5 其值固定為 0x05
- NMETHODS 字段指示其后的 METHOD 字段所占的字節(jié)數(shù), 其本身占 1 字節(jié)
- METHODS 字段為可變長(zhǎng)字段, 用來(lái)指示客戶(hù)端和代理服務(wù)器之間的認(rèn)證方法, 其長(zhǎng)度區(qū)間為 [1, 255] 個(gè)字節(jié), 即客戶(hù)端在向代理服務(wù)器發(fā)起握手時(shí)同時(shí)聲明其所支持的認(rèn)證方法的列表, 代理服務(wù)器會(huì)從中選擇一個(gè)方法作為接下來(lái)與客戶(hù)端進(jìn)行認(rèn)證的方法, 所以對(duì)于 Socks 5 協(xié)議來(lái)說(shuō), 客戶(hù)端發(fā)起的握手實(shí)際上本身也是啟動(dòng)了一個(gè)協(xié)商過(guò)程
代理服務(wù)器在收到客戶(hù)端發(fā)起的請(qǐng)求之后, 向客戶(hù)端發(fā)回握手響應(yīng), 其數(shù)據(jù)包格式如下:
- 其中 VER 字段與客戶(hù)端請(qǐng)求數(shù)據(jù)包的 VER 字段含義相同, 表征協(xié)議版本, 固定為 0x05
- METHOD 字段表征代理服務(wù)器所選擇的協(xié)議版本, 長(zhǎng)度為 1 字節(jié), 當(dāng)然代理服務(wù)器可能對(duì)于客戶(hù)端所聲明的所有認(rèn)證方法都不支持, 此時(shí)代理服務(wù)器將 METHOD 字段值為 0xFF, 客戶(hù)端收到該數(shù)據(jù)包時(shí)便知曉代理服務(wù)器不支持自己所聲明的認(rèn)證方法, 即協(xié)商失敗, 客戶(hù)端應(yīng)主動(dòng)關(guān)閉 TCP 連接
Socks 協(xié)議支持多種認(rèn)證方法, 每一種認(rèn)證方法都有一個(gè)對(duì)應(yīng)的編號(hào), Socks 握手環(huán)節(jié)的 METHOD 字段便存放了認(rèn)證方法的編號(hào), 如 0x00 代表不需要認(rèn)證, 0x02 代表用戶(hù)名/密碼方式的認(rèn)證等, 不同的認(rèn)證方法將導(dǎo)致后續(xù)不同的認(rèn)證流程, 本文不一一展開(kāi)敘述相關(guān)的認(rèn)證流程
當(dāng)認(rèn)證過(guò)程通過(guò)后, Socks 握手正式完成, 此時(shí)客戶(hù)端向代理服務(wù)器發(fā)起正式請(qǐng)求以指示所要訪問(wèn)的目標(biāo)進(jìn)程的地址, 端口等信息, 其數(shù)據(jù)包格式如下所示:
- VER 字段表征 Socks 版本, 固定為 0x05
- CMD 字段指示連接的類(lèi)型, 占 1 個(gè)字節(jié), 共有 3 個(gè)取值, 分別為 0x01 (CONNECT), 0x02 (BIND), 0x03 (UDP ASSOCIATE), 關(guān)于每個(gè)值的含義將在下面討論
- RSV 字段為保留字段, 占 1 個(gè)字節(jié), 固定為 0x00
- ATYP 字段指示地址類(lèi)型 (DST.ADDR 字段的類(lèi)型), 0x01 為 IPv4 地址, 0x03 為域名, 0x04 為 IPv6 地址
- DST.ADDR 字段指示客戶(hù)端所要訪問(wèn)的目的地址, 這是一個(gè)變長(zhǎng)字段, 其長(zhǎng)度由前一個(gè)字段的值來(lái)決定, 當(dāng) ATYP 字段的值為 0x01 時(shí), 表示該字段為 IPv4 地址, 從而長(zhǎng)度為 4 個(gè)字節(jié), 當(dāng) ATYP 字段的值為 0x03 時(shí)代表地址類(lèi)型為域名, 此時(shí) DST.ADDR 字段的第一個(gè)字節(jié)的值指示其后所跟隨的域名所占的字節(jié)數(shù), 當(dāng) ATYP 字段的值為 0x04 時(shí), 表示該字段為 IPv6 地址, 其長(zhǎng)度為 16 個(gè)字節(jié)
代理服務(wù)器在收到以上請(qǐng)求后, 其返回的數(shù)據(jù)包格式如下:
VER 字段占 1 字節(jié), 表征協(xié)議版本, 固定為 0x05
REP 字段占 1 字節(jié), 可以理解為狀態(tài)碼, 它的值表征了此次連接的狀態(tài):
0x00 連接成功
0x01 代理服務(wù)器出錯(cuò)
0x02 連接不允許
0x03 網(wǎng)絡(luò)不可達(dá)
0x04 主機(jī)不可達(dá)
0x05 連接被拒絕
0x06 TTL 到期
0x07 命令 (CMD) 不支持
0x08 地址類(lèi)型不支持
0x09 ~ 0xFF 目前沒(méi)有分配
RSV 字段占 1 字節(jié), 為保留字段, 固定為 0x00
ATYP 字段與請(qǐng)求的 ATYP 字段含義相同
BND.ADDR 與 BND.PORT 的含義隨請(qǐng)求中的 CMD 的不同而不同, 下面我們依次展開(kāi)討論 3 種 CMD: CONNECT, BIND 以及 UDP ASSOCIATE
當(dāng)客戶(hù)端發(fā)往代理服務(wù)器的數(shù)據(jù)包的 CMD 字段的值為 0x01 時(shí), 代表 CONNECT, 此時(shí) DST.ADDR 和 DST.PORT 指示客戶(hù)端所想要訪問(wèn)的目標(biāo)主機(jī)的地址和端口, 代理服務(wù)器在收到該請(qǐng)求后建立 "代理服務(wù)器到目標(biāo)主機(jī)" 的 TCP 連接, 并將代理服務(wù)器分配的 IP 地址和端口在返回的數(shù)據(jù)包中的 BIND.ADDR 和 BIND.PORT 字段中告訴客戶(hù)端
當(dāng)客戶(hù)端發(fā)往代理服務(wù)器的數(shù)據(jù)包的 CMD 字段的值為 0x02 時(shí), 代表 BIND, BIND 主要用在雙向連接場(chǎng)景中, 最典型的例子為 FTP, FTP 會(huì)建立兩個(gè)連接, 第一個(gè)連接為 客戶(hù)端→服務(wù)器, 用于發(fā)送指令及狀態(tài)信息, 第二個(gè)連接為 服務(wù)器→客戶(hù)端, 用于傳輸數(shù)據(jù), 在 Socks 5 協(xié)議中, 客戶(hù)端只有首先發(fā)送 CONNECT 連接之后, 才允許發(fā)送 BIND 連接, 客戶(hù)端在向代理服務(wù)器發(fā)送 BIND 請(qǐng)求之后, 代理服務(wù)器將會(huì)向客戶(hù)端發(fā)起兩次回復(fù), 其中第一次回復(fù)發(fā)生在代理服務(wù)器建立并綁定用于接收 目標(biāo)主機(jī)→代理服務(wù)器 連接的套接字時(shí)后 (此時(shí)只是代理服務(wù)器自己創(chuàng)建套接字, 目標(biāo)主機(jī)到代理服務(wù)器的連接還沒(méi)有建立), 代理服務(wù)器在 BIND.ADDR 和 BIND.PORT 字段指示其用于監(jiān)聽(tīng)目標(biāo)主機(jī)連接的地址和端口, 當(dāng)目標(biāo)主機(jī)→代理服務(wù)器連接建立完成后, 代理服務(wù)器會(huì)向客戶(hù)端發(fā)送第二次回復(fù), 其中 BIND.ADDR 和 BIND.PORT 指示目標(biāo)主機(jī)的地址和端口
當(dāng)客戶(hù)端發(fā)往代理服務(wù)器的數(shù)據(jù)包的 CMD 字段的值為 0x03 時(shí), 代表 UDP ASSOCIATE, 這里的細(xì)節(jié)在下一節(jié)討論
Socks 5 UDP 穿透
當(dāng) CMD 字段的值為 0x03 時(shí), 此時(shí)客戶(hù)端發(fā)起了 UDP 穿透請(qǐng)求, 此時(shí) DST.ADDR 和 DST.PORT 為客戶(hù)端所要發(fā)送 UDP 數(shù)據(jù)包所使用的地址和端口, 代理服務(wù)器返回的數(shù)據(jù)包的 BIND.ADDR 和 BIND.PORT 為客戶(hù)端要發(fā)送 UDP 包所使用的目標(biāo)地址和端口 (代理服務(wù)器的 UDP 中繼進(jìn)程的地址和端口), 此時(shí) UDP 穿透通道建立完成, 但此時(shí)不能向常規(guī)發(fā)送 UDP 包那樣直接發(fā)送, 因?yàn)榻刂鼓壳斑€沒(méi)有將目標(biāo)主機(jī)的地址和端口告訴 UDP 中繼, 在 Socks 5 協(xié)議中, 客戶(hù)端發(fā)往 UDP 中繼的數(shù)據(jù)包格式實(shí)際如下所示:
- RSV 字段為保留字段, 占兩個(gè)字節(jié), 其值固定為 0x0000
- FRAG 字段為占 1 個(gè)字節(jié), 指示當(dāng)前 UDP 分片的編號(hào)
- ATYP 指示地址類(lèi)型
- DST.ADDR 和 DST.PORT 為所要發(fā)往的目標(biāo)主機(jī)的地址和端口
- DATA 字段為原始的 UDP 報(bào)文 (的數(shù)據(jù)部分?)
代理服務(wù)器收到該數(shù)據(jù)包后, 提取 DATA 字段即為客戶(hù)端想要向目標(biāo)主機(jī)發(fā)送的原始的 UDP 報(bào)文(的數(shù)據(jù)部分?), 此時(shí)根據(jù) DST.ADDR 和 DST.PORT 字段將 UDP 報(bào)文投遞給目標(biāo)主機(jī), 所以從目標(biāo)主機(jī)來(lái)看這就是一次樸素的 UDP 通信, 代理服務(wù)器收到目標(biāo)主機(jī)響應(yīng)的數(shù)據(jù)包之后也會(huì)將 UDP 報(bào)文按上圖所示的格式組裝后發(fā)送給客戶(hù)端, 前面提到, Socks 5 協(xié)議的 UDP 穿透需要首先由客戶(hù)端發(fā)起 CMD 為 UDP ASSOCIATE 的 TCP 請(qǐng)求, 整個(gè) UDP 穿透與該 TCP 連接的生命周期相同, 當(dāng)該連接中止時(shí), UDP 穿透也隨之中止
可以閱讀 Chromium V8 引擎實(shí)現(xiàn)的 Socks 5:
部署調(diào)試
選擇的服務(wù)器系統(tǒng):centos7
SSH到服務(wù)器,依次執(zhí)行下面的代碼:(每一行需要分別執(zhí)行)
sudo su root yum -y install wget get –no-check-certificate [https://raw.github.com/Lozy/danted/master/install.sh](https://raw.github.com/Lozy/danted/master/install.sh) -O install.sh bash install.sh --port=9926 --user=Frank --passwd=9928
代碼執(zhí)行完成,這樣你就搭建了屬于自己的Socks5代理逞刷,ip是就是服務(wù)器ip地址,端口:9926 用戶(hù)名:Frank 密碼:9928
shun 1234
- if you want to add user
/etc/init.d/sockd adduser USERNAME PASSWORD
- if you want to uninstall, using this command
bash install.sh --uninstall
開(kāi)放端口 iptables -I INPUT -ptcp --dport 1298 -夕土。 ACCEPT
開(kāi)機(jī)嘗試
chkconfig --add sockd
systemctl enable sockd.service
啟動(dòng)
systemctl start sockd
注意坑點(diǎn):
1.systemctl start sockd
2.有密碼的qq支持,微信有時(shí)候可以響應(yīng)
3.使用proxifier全局模式可以搞
服務(wù)器帶寬不行效果有點(diǎn)費(fèi)勁,
qq 和 proxifier 都可以直接代理(Google也可以)
直接配置Google的我試了一下不行,用nodejs搭了一個(gè)沒(méi)有密碼校驗(yàn)的,Google可以訪問(wèn).