SOCKS5协议/RFC1928阅读笔记
基于TCP的连接
服务器通常开放在1080端口,协议过程如下:
- 客户端连接到服务端,发送**版本标识和认证方式选择(version identifier/method selection)**消息
版本(VER) | 认证方法数(NMETHODS) | 方法(METHODS) |
---|---|---|
1字节,=0x05 | 1字节 | 1到255字节 |
- 服务端选择一个支持的方法,并返回一个**方法选择(method selection)**消息
版本(VER) | 方法(METHOD) |
---|---|
1字节 | 1字节 |
如果服务端返回的认证方式(METHOD)客户端不予支持,则客户端必须关闭连接。
当前定义的认证方式有:
- 0x00:不需要认证
- 0x01:GSSAPI
- 0x02:用户名密码认证
- 0x03~0x7F:由IANA分派
- 0x80~0xFE:保留用于私有方法
- 0xFF:没有支持的方法
当认证方式协商完毕后,客户端和服务端将根据对应的方式进入相应的子协议。
- 当1和2步的握手完成后,客户端向服务端发送请求的细节,**SOCKS请求(SOCKS request)**描述如下
版本(VER) | 命令(CMD) | 保留(RSV) | 地址类型(ATYP) | 目的地址(DST.ADDR) | 目的端口(DST.PORT) |
---|---|---|---|---|---|
1字节,=0x05 | 1字节 | 1字节,=0x00 | 1字节 | 可变的 | 2字节,网络序 |
其中,**命令字(CMD)**定义如下:
- 0x01:连接(CONNECT)
- 0x02:绑定(BIND)
- 0x03:UDP连接(UDP ASSOCIATE)
**地址类型(ATYP)**定义如下:
- 0x01:IPv4地址,此时DST.ADDR长度为4字节
- 0x03:域名,此时DST.ADDR的第一个字节用于指定字符串长度,后续一个无'\0'结尾的字符串
- 0x04:IPv6地址,此时DST.ADDR长度为16字节
服务端会根据请求的内容返回一到多条消息。
此外,如果认证机制带有额外的封装方式,上述消息应当被封装在其中。
- SOCKS请求对应的服务端的回包描述如下
版本(VER) | 响应(REP) | 保留(RSV) | 地址类型(ATYP) | 绑定地址(DND.ADDR) | 绑定端口(DND.PORT) |
---|---|---|---|---|---|
1字节,=0x05 | 1字节 | 1字节,=0x00 | 1字节 | 可变的 | 2字节,网络序 |
其中,**响应(REP)**定义如下:
- 0x00:成功
- 0x01:服务端常规错误
- 0x02:连接不被规则允许
- 0x03:网络不可达
- 0x04:主机不可达
- 0x05:连接被拒绝
- 0x06:TTL超时
- 0x07:命令不支持
- 0x08:地址类型不支持
- 0x09~0xFF:尚未分配
地址类型、地址和端口的定义参见SOCKS请求。
此外,如果认证机制带有额外的封装方式,上述消息应当被封装在其中。
- 开始数据传输
若服务端的回包不是一个错误(REP为非0值),那么服务端必须在发完回包后(保证回包正确发送)关闭连接,且连接关闭不应当超过10秒。
如果回包是一个正确状态(REP=0),那么客户端将开始发送数据,若认证方式存在相应的封装,服务端将进行解封装操作,并将数据发送到目的主机。
三种命令的解释
CONNECT命令
通知服务端连接到某个地址,回包中的BND.ADDR表明服务端用于连接到目的主机的地址(这个值可能和客户端访问socks服务的地址不同),BND.PORT用于表明服务端连接到目的主机的端口(实际编程中,在connect操作后可以用getsockname获取这一信息)。
BIND命令
BIND请求被用于那些需要服务器反向连接客户端的协议(比如FTP)。这里要求客户端首先使用CONNECT命令建立一个主连接,而后建立一个新的连接并使用BIND命令来通知SOCKS服务器绑定一个地址来接收请求。
请求中的DST.ADDR和DST.PORT将被服务器用于评估连接。
SOCKS服务端将会返回两个回包,第一个回包在服务端创建并绑定一个SOCKS端口后进行,BND.ADDR和BND.PORT填写绑定在服务端上的地址和端口。客户端将使用这些信息来映射协议中的地址。
第二个回包仅在服务端成功或失败地接受一个传入连接时发送,BND.ADDR和BND.PORT包含远端连入的地址和端口。
之后将使用这个连接发送后续的数据。
注:但是这个地方有一个问题,在这种设计下,客户端只能接受一个连接。在stackoverflow上搜索后,看到了这样的答复:
You need a separate BIND request for each connection you want to accept, as there is only 1 notification sent back by the SOCKS proxy when a client connects to the bound port. Whether or not the SOCKS5 proxy allows multiple BIND requests on the same IP/Port depends on the proxy's implementation.
换句话说,当一个连接被成功接受后,客户端可以再次发起连接进行BIND操作绑定相同的地址,从而接受更多的请求。
UDP ASSOCIATE
暂时用不到,略。
基于UDP的连接
暂时用不到,略。