本文由TZWSOHO通过收集网络资料整理而成(百度百科和英文维基百科),文中某些地方可能由于笔者本人技术水平有限而造成翻译上甚至是个人理解上的错漏,欢迎路过本文的各路英雄斧正。另若有需要转载时请高抬贵手标明出处,万分感谢!
SOCKS v4 代理服务器由于用户验证机制没有 v5 版完善现已不多见,但其实现原理与 v5 版有很多类似之处,且较 v5 版为简单,估作为知识点的引导在此先作介绍。而 v4a 版只对 v4 版增加了域名解析的功能,其他功能不变,故在此一并讲述。
SOCKS v4/v4a 定义了两种操作: CONNECT 和 BIND 。
1. CONNECT
当一台内网计算机(客户端)意图连接外网的一台计算机时,客户端首先会发送一个 CONNECT 请求数据包到代理服务器,通过此请求代理服务器将与外网计算机建立连接,若代理服务器与指定的外网计算机的连接建立成功,则之后客户端与该外网计算机的通讯便完全通过代理服务器作为数据交换的媒介。 v4 版的 CONNECT 请求数据包的格式如下:
字段名 | VN | CD | DSTPORT | DSTIP | User ID | NULL |
字段 默认值 | 4 | 1 | 外网计算机通讯端口 | 外网计算机 IP | 用户 ID | 0 |
字段长度(字节) | 1 | 1 | 2 | 4 | 可变 | 1 |
VN 是 SOCKS 的版本,此字段值为 4.
CD 为操作类型标识, CONNECT 操作定义为 1 , BIND 操作定义为 2.
DSTPORT 为目标计算机的通讯 TCP 端口(网络字节顺序)。
DSTIP 为目标计算机的 IP 地址(网络字节顺序)。
USERID 为客户端登录用户名,长度可变。
数据包最后以 NULL 字段( 1 字节,值为 0 )结束。
代理服务器接收到此数据包后,将尝试根据数据包的 DSTIP 和 DSTPORT 与目标计算机进行连接,然后根据连接的结果回复一个数据包给客户端。此回复数据包的格式如下:
字段名 | VN | CD | DSTPORT | DSTIP |
字段默认值 | 0 | 连接状态 | 目标主机端口 | 目标主机 IP |
字段长度(字节) | 1 | 1 | 2 | 4 |
VN 是返回代码的版本,此字段值为 0 。
CD 是连接状态的编码,具体意义如下:
l 90 ,请求得到允许;
l 91 ,请求被拒绝或失败;
l 92 ,由于 SOCKS 服务器无法连接到客户端的 identd (一个验证身份的进程)或无法连接到目标主机,请求被拒绝;
l 93 ,由于客户端程序与 identd 报告的用户身份不同,连接被拒绝。
DSTPORT 与 DSTIP 与请求包中的内容相同,但被忽略。
若请求被拒绝或失败,则代理服务器将立即关闭与客户端的通讯连接。若请求成功,则代理服务器就充当客户端与目的主机之间进行双向传递,对客户端而言,就如同直接在与目的主机相连。
2. BIND
当客户端意图接收外部传入的连接时,将会发送一个 BIND 请求数据包至代理服务器,通过代理服务器建立指定的监听端口来监听外部连接。 BIND 请求数据包的格式与 CONNECT 请求数据包格式一样,不同的是 CD 字段的值为 2 。
下面举例说明一台 identd 为 Fred 的客户端主机尝试通过代理服务器连接到 66.102.7.99:80 ,且连接成功建立的过程中双方发送的数据包:
客户端: 0x04 | 0x01 | 0x00 0x50 | 0x42 0x66 0x07 0x63 | 0x46 0x72 0x65 0x64 | 0x00
代理服务器: 0x00 | 0x5a | 0x00 0x50 | 0x42 0x66 0x07 0x63
其中 0x46 0x72 0x65 0x64 为字符串 Fred 的 ASCII 码。
SOCKS v4a 是对 v4 的简单扩展,专门对于客户端无法解析某个域名而设,其请求数据包的格式如下:
字段名 | VN | CD | DSTPORT | DSTIP | User ID | NULL | HOST | NULL |
字段值 | 4 | 1 或 2 | 目标主机端口 | 0.0.0.x | 用户 ID | 0 | 目标主机 | 0 |
字段长度(字节) | 1 | 1 | 2 | 4 | 可变 | 1 | 可变 | 1 |
若代理服务器读取到 DSTIP 的前三字节为 0 且第四字节非零(即 IP 为 0.0.0.x ,此 IP 在实际应用中是不存在的),则代理服务器需要读取 HOST 字段并且解析域名,最后与解析得到的 IP 尝试建立连接。请求数据包中的其他字段意义与 v4 版本一样。
代理服务器回复客户端的数据包格式与 v4 版本一样。