Socks5 RFC1928协议中文版

除了这个意译版rfc1928外,其他人写的好像也有错误,都是一知半解。
☆ RFC 1928意译版(非直译版)

http://www.ietf.org/rfc/rfc1928.txt
http://www.sczgroup.org/network/200503311423.txt

SOCKS协议位于传输层(TCP/UDP等)与应用层之间,因而显然地位于网络层(IP)之上。
诸如IP层报文转发、ICMP协议等等都因太低层而与SOCKS协议无关。

SOCKS 4不支持认证、UDP协议以及远程解析FQDN。SOCKS 5支持。

SOCKS Server缺省侦听在1080/TCP口。这是SOCKS Client连接到SOCKS Server之后发
送的第一个报文:

+----+----------+----------+
|VER | NMETHODS | METHODS  |
+----+----------+----------+
| 1  |    1     | 1 to 255 |
+----+----------+----------+

对于SOCKS 5,VER字段为0x05,版本4对应0x04。NMETHODS字段指定METHODS域的字节
数。不知NMETHODS可以为0否,看上图所示,可取值[1,255]。METHODS字段有多少字
节(假设不重复),就意味着SOCKS Client支持多少种认证机制。

SOCKS Server从METHODS字段中选中一个字节(一种认证机制),并向SOCKS Client发
送响应报文:

+----+--------+
|VER | METHOD |
+----+--------+
| 1  |   1    |
+----+--------+

目前可用METHOD值有:

0x00        NO AUTHENTICATION REQUIRED(无需认证)
0x01        GSSAPI
0x02        USERNAME/PASSWORD(用户名/口令认证机制)
0x03-0x7F   IANA ASSIGNED
0x80-0xFE   RESERVED FOR PRIVATE METHODS(私有认证机制)
0xFF        NO ACCEPTABLE METHODS(完全不兼容)

如果SOCKS Server响应以0xFF,表示SOCKS Server与SOCKS Client完全不兼容,
SOCKS Client必须关闭TCP连接。认证机制协商完成后,SOCKS Client与
SOCKS Server进行认证机制相关的子协商,参看其它文档。为保持最广泛兼容性,
SOCKS Client、SOCKS Server必须支持0x01,同时应该支持0x02。

认证机制相关的子协商完成后,SOCKS Client提交转发请求:

+----+-----+-------+------+----------+----------+
|VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+

VER         对于版本5这里是0x05

CMD         可取如下值:

            0x01    CONNECT
            0x02    BIND
            0x03    UDP ASSOCIATE

RSV         保留字段,必须为0x00

ATYP        用于指明DST.ADDR域的类型,可取如下值:

            0x01    IPv4地址
            0x03    FQDN(全称域名)
            0x04    IPv6地址

DST.ADDR    CMD相关的地址信息,不要为DST所迷惑

            如果是IPv4地址,这里是big-endian序的4字节数据

            如果是FQDN,比如"www.nsfocus.net",这里将是:

            0F 77 77 77 2E 6E 73 66 6F 63 75 73 2E 6E 65 74

            注意,没有结尾的NUL字符,非ASCIZ串,第一字节是长度域

            如果是IPv6地址,这里是16字节数据。

DST.PORT    CMD相关的端口信息,big-endian序的2字节数据

SOCKS Server评估来自SOCKS Client的转发请求并发送响应报文:

+----+-----+-------+------+----------+----------+
|VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+

VER         对于版本5这里是0x05

REP         可取如下值:

            0x00        成功
            0x01        一般性失败
            0x02        规则不允许转发
            0x03        网络不可达
            0x04        主机不可达
            0x05        连接拒绝
            0x06        TTL超时
            0x07        不支持请求包中的CMD
            0x08        不支持请求包中的ATYP
            0x09-0xFF   unassigned

RSV         保留字段,必须为0x00

ATYP        用于指明BND.ADDR域的类型

BND.ADDR    CMD相关的地址信息,不要为BND所迷惑

BND.PORT    CMD相关的端口信息,big-endian序的2字节数据

1) CONNECT命令

假设CMD为CONNECT,SOCKS Client、SOCKS Server之间通信的相关四元组是:

SOCKSCLIENT.ADDR,SOCKSCLIENT.PORT,SOCKSSERVER.ADDR,SOCKSSERVER.PORT

一般SOCKSSERVER.PORT是1080/TCP。

CONNECT请求包中的DST.ADDR/DST.PORT指明转发目的地。SOCKS Server可以靠
DST.ADDR、DST.PORT、SOCKSCLIENT.ADDR、SOCKSCLIENT.PORT进行评估,以决定建立
到转发目的地的TCP连接还是拒绝转发。

假设规则允许转发并且成功建立到转发目的地的TCP连接,相关四元组是:

BND.ADDR,BND.PORT,DST.ADDR,DST.PORT

此时SOCKS Server向SOCKS Client发送的CONNECT响应包中将指明BND.ADDR/BND.PORT。
注意,BND.ADDR可能不同于SOCKSSERVER.ADDR,SOCKS Server所在主机可能是多目(
multi-homed)主机。

假设拒绝转发或未能成功建立到转发目的地的TCP连接,CONNECT响应包中REP字段将
指明具体原因。

响应包中REP非零时表示失败,SOCKS Server必须在发送响应包后不久(不超过10s)关
闭与SOCKS Client之间的TCP连接。

响应包中REP为零时表示成功。之后SOCKS Client直接在当前TCP连接上发送待转发数
据。

2) BIND命令

假设CMD为BIND。这多用于FTP协议,FTP协议在某些情况下要求FTP Server主动建立
到FTP Client的连接,即FTP数据流。

FTP Client - SOCKS Client - SOCKS Server - FTP Server

a. FTP Client试图建立FTP控制流。SOCKS Client向SOCKS Server发送CONNECT请求,
   后者响应请求,最终FTP控制流建立。

   CONNECT请求包中指明FTPSERVER.ADDR/FTPSERVER.PORT。

b. FTP Client试图建立FTP数据流。SOCKS Client建立新的到SOCKS Server的TCP连
   接,并在新的TCP连接上发送BIND请求。

   BIND请求包中仍然指明FTPSERVER.ADDR/FTPSERVER.PORT。SOCKS Server应该据此
   进行评估。

   SOCKS Server收到BIND请求,创建新套接字,侦听在AddrA/PortA上,并向SOCKS
   Client发送第一个BIND响应包,包中BND.ADDR/BND.PORT即AddrA/PortA。

c. SOCKS Client收到第一个BIND响应包。FTP Client通过FTP控制流向FTP Server发
   送PORT命令,通知FTP Server应该主动建立到AddrA/PortA的TCP连接。

d. FTP Server收到PORT命令,主动建立到AddrA/PortA的TCP连接,假设TCP连接相关
   四元组是:

   AddrB,PortB,AddrA,PortA

e. SOCKS Server收到来自FTP Server的TCP连接请求,向SOCKS Client发送第二个
   BIND响应包,包中BND.ADDR/BND.PORT即AddrB/PortB。然后SOCKS Server开始转
   发FTP数据流。

下面是一些讨论记录:

scz

为什么需要发送第二个BIND响应包,指明AddrB/PortB的意义何在。

knightmare@apue

指明AddrB/PortB的意义在于,FTP Client出于安全考虑,会检查FTP数据流的源IP、
源端口,比如FTP数据流的源端只允许是FTPSERVER.ADDR/20。

scz

knightmare的答案是正确的,但我的疑惑可能源于我对SOCKS协议的错误理解,以至
提出一个产生歧义的问题。事实上应该查看David Koblas的原始文档以理解BIND请求
的全过程。前面关于FTP数据流的描述部分已做了修正,因此看不出提问的缘由了。

3) UDP ASSOCIATE命令

假设CMD为UDP ASSOCIATE。此时DST.ADDR与DST.PORT指明发送UDP报文时的源IP、源
端口,而不是UDP转发目的地,SOCKS Server可以据此进行评估以决定是否进行UDP转
发。如果SOCKS Client发送UDP ASSOCIATE命令时无法提供DST.ADDR与DST.PORT,则
必须将这两个域置零。

下面是一些讨论记录:

scz

什么情况下SOCKS Client发送UDP ASSOCIATE命令,又无法提供DST.ADDR与DST.PORT,
或者说出于什么考虑才需要刻意将这两个域置零。有现实例子存在吗。

shixudong@163.com

考虑这种情况:

Application Client - SOCKS Client - NAT - SOCKS Server - Application Server

SOCKS Client在UDP ASSOCIATE命令中指明DST.ADDR/DST.PORT,SOCKS Server靠这些
信息决定是否转发某个UDP报文。上图中SOCKS Client与SOCKS Server之间有NAT,前
者无法预知UDP报文经过NAT后源IP、源端口会变成什么样,但肯定会变,因此前者无
法提前在UDP ASSOCIATE命令中指明DST.ADDR/DST.PORT,如果强行指定非零值,后者
会检测到待转发UDP报文的源IP、源端口与DST.ADDR/DST.PORT不匹配而拒绝转发。针
对这种情况,RFC 1928建议SOCKS Client将DST.ADDR/DST.PORT置零,SOCKS Server
此时不再检查待转发UDP报文的源IP、源端口。

在一条TCP连接上SOCKS Client向SOCKS Server发送了UDP ASSOCIATE命令,后续UDP
转发要求此TCP连接继续维持,此TCP连接关闭时相应的UDP转发也将中止。换句话说,
UDP转发必然伴随着一个TCP连接,这将消耗额外的资源。

SOCKS Server向SOCKS Client发送UDP ASSOCIATE响应包,BND.ADDR/BND.PORT指明
SOCKS Client应向哪里发送待转发UDP报文。

对于UDP转发,SOCKS Client发送出去的UDP数据区如下:

+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
+----+------+------+----------+----------+----------+
| 2  |  1   |  1   | Variable |    2     | Variable |
+----+------+------+----------+----------+----------+

RSV         保留字段,必须为0x0000

FRAG        Current fragment number

            0x00        这是一个非碎片的SOCKS UDP报文
            0x01-0x7F   SOCKS碎片序号
            0x80-0xFF   最高位置1表示碎片序列结束,即这是最后一个SOCKS碎片

ATYP        用于指明DST.ADDR域的类型,可取如下值:

            0x01    IPv4地址
            0x03    FQDN(全称域名)
            0x04    IPv6地址

DST.ADDR    转发目标地址

DST.PORT    转发目标端口

DATA        原始UDP数据区

SOCKS Server静静地为SOCKS Client进行UDP转发,并不通知后者转发完成还是被拒
绝。

FRAG用于支持SOCKS碎片。SOCKS碎片接收方一般实现有重组队列与重组定时器。假设
重组定时器超时或者低序SOCKS碎片后于高序SOCKS碎片到达重组队列,此时必须重置
重组队列。重组定时器不得小于5秒。应该尽可能地避免出现SOCKS碎片。

是否支持SOCKS碎片是可选的,如果一个SOCKS实现不支持SOCKS碎片,则必须丢弃所
有接收到的SOCKS碎片,即那些FRAG字段非零的SOCKS UDP报文。

由于SOCKS实现在支持UDP转发时会在原始UDP数据区前增加一个SOCKS协议相关的头,
因此为UDP数据区分配空间时要为这个头留足空间:

ATYP    头占用字节  原因
0x01    10          IPv4地址占4字节,4+6=10
0x03    262         长度域是一个字节,因此最大0xFF,1+255+6=262
0x04    20          这里我怀疑是笔误,IPv6地址占16字节,16+6=22

我怀疑RFC 1928这里有笔误,写信询问mleech@bnr.ca、ietf-web@ietf.org去了。
 

 

SOCKS 4A是SOCKS 4协议的简单扩展,允许客户端对无法解析的目的主机,进行自行规定。
客户端对DSTIP的头三个字节设定为NULL,最后一个字节为非零;对应的IP地址就是0.0.0.x,其中x是非零,这当然不可能是目的主机的地址,这样即使客户端可以解析域名,对此也不会发生冲突。USERID以紧跟的NULL字节作结尾,客户端必须发送目的主机的域名,并以另一个NULL字节作结尾。CONNECT和BIND请求的时候,都要按照这种格式(以字节为单位):

+----+----+----+----+----+----+----+----+----+----+....+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP 0.0.0.x | USERID |NULL| HOSTNAME |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+----+----+....+----+
1 1 2 4 variable 1 variable 1

使用4a协议的服务器必须检查请求包里的DSTIP字段,如果表示地址0.0.0.x,x是非零结尾,那么服务器就得读取客户端所发包中的域名字段,然后服务器就得解析这个域名,可以的话,对目的主机进行连接。

 

 

 

 

SOCKS协议最初由David Koblas设计,后经Ying-Da Lee改进成SOCKS 4协议。

SOCKS4协议主要是如下几个RFC
http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol
http://www.rfc-editor.org/rfc/rfc1928.txt
http://www.smartftp.com/Products/SmartFTP/RFC/socks4a.protocol
 


SOCKS 4只支持TCP转发。

请求报文格式如下:

+----+----+----+----+----+----+----+----+----+----+...+----+
| VN | CD | DSTPORT |      DSTIP        | USERID      |NULL|
+----+----+----+----+----+----+----+----+----+----+...+----+
   1    1      2              4           variable       1

VN      SOCKS协议版本号,应该是0x04

CD      SOCKS命令,可取如下值:

        0x01    CONNECT
        0x02    BIND

DSTPORT CD相关的端口信息

DSTIP   CD相关的地址信息

USERID  客户方的USERID

NULL    0x00

响应报文格式如下:

+----+----+----+----+----+----+----+----+
| VN | CD | DSTPORT |      DSTIP        |
+----+----+----+----+----+----+----+----+
   1    1      2              4

VN      应该为0x00而不是0x04

CD      可取如下值:

        0x5A    允许转发
        0x5B    拒绝转发,一般性失败
        0x5C    拒绝转发,SOCKS 4 Server无法连接到SOCS 4 Client所在主机的
                IDENT服务
        0x5D    拒绝转发,请求报文中的USERID与IDENT服务返回值不相符

DSTPORT CD相关的端口信息

DSTIP   CD相关的地址信息

1) CONNECT命令

对于CONNECT请求,DSTIP/DSTPORT指明转发目的地。

SOCKS 4 Server根据源IP、DSTPORT、DSTIP、USERID以及可从SOCS 4 Client所在主
机的IDENT服务(RFC 1413)获取的信息进行综合评估,以决定建立相应连接还是拒绝
转发。

假设CONNECT请求被允许,SOCKS 4 Server试图建立到转发目的地的TCP连接,然后向
SOCKS 4 Client发送响应报文,指明是否成功建立转发连接。

如果CONNECT请求被拒绝,SOCKS 4 Server也向SOCKS 4 Client发送响应报文,随后
立即关闭连接。

CONNECT响应包中只有VN、CD字段有意义,DSTPORT、DSTIP字段被忽略。如果CD等于
0x5A,表示成功建立转发连接,之后SOCKS 4 Client直接在当前TCP连接上发送待转
发数据。

2) BIND命令

FTP协议在某些情况下要求FTP Server主动建立到FTP Client的连接,即FTP数据流。

FTP Client - SOCKS 4 Client - SOCKS 4 Server - FTP Server

a. FTP Client试图建立FTP控制流。SOCKS 4 Client向SOCKS 4 Server发送CONNECT
   请求,后者响应请求,最终FTP控制流建立。

   CONNECT请求包中指明FTPSERVER.ADDR/FTPSERVER.PORT。

b. FTP Client试图建立FTP数据流。SOCKS 4 Client建立新的到SOCKS 4 Server的
   TCP连接,并在新的TCP连接上发送BIND请求。

   BIND请求包中仍然指明FTPSERVER.ADDR/FTPSERVER.PORT。

   SOCKS 4 Server收到BIND请求,根据这两个信息以及USERID对BIND请求进行评估。
   创建新套接字,侦听在AddrA/PortA上,并向SOCKS 4 Client发送第一个BIND响应
   包。

   BIND响应包中CD不等于0x5A时表示失败,包中DSTPORT、DSTIP字段被忽略。

   BIND响应包中CD等于0x5A时,包中DSTIP/DSTPORT对应AddrA/PortA。如果DSTIP等
   于0(INADDR_ANY),SOCKS 4 Client应将其替换成SOCKS 4 Server的IP,当SOCKS
   4 Server非多目(multi-homed)主机时就可能出现这种情况。

c. SOCKS 4 Client收到第一个BIND响应包。

   FTP Client调用getsockname(不是getpeername)获取AddrA/PortA,通过FTP控制
   流向FTP Server发送PORT命令,通知FTP Server应该主动建立到AddrA/PortA的
   TCP连接。

d. FTP Server收到PORT命令,主动建立到AddrA/PortA的TCP连接,假设TCP连接相关
   四元组是:

   AddrB,PortB,AddrA,PortA

e. SOCKS 4 Server收到来自FTP Server的TCP连接请求,检查这条入连接的源IP(
   AddrB)是否与FTPSERVER.ADDR匹配,然后向SOCKS 4 Client发送第二个BIND响应
   包。

   源IP不匹配时第二个BIND响应包中CD字段设为0x5B,然后SOCKS 4 Server关闭这
   条用于发送第二个BIND响应包的TCP连接,同时关闭与FTP Server之间的TCP连接,
   但主TCP连接(与CONNECT请求相关的那条TCP连接)继续保持中。

   源IP匹配时CD字段设为0x5A。然后SOCKS 4 Server开始转发FTP数据流。

   无论如何,第二个BIND响应包中DSTPORT、DSTIP字段被忽略。

对于CONNECT、BIND请求,SOCKS 4 Server有一个定时器(当前CSTC实现采用两分钟)。
假设定时器超时,而SOCKS 4 Server与Application Server之间的TCP连接(出连接或
入连接)仍未建立,SOCKS 4 Server将关闭与SOCKS 4 Client之间相应的TCP连接并放
弃相应的转发。

 

 

 

SOCKS   5协议详解        
    
    笔者在实际学习中,由于在有些软件用到了socks5(如oicq,icq等),对其原理不甚了解,相信很多朋友对其也不是很了解,于是仔细研读了一下rfc1928,觉得有必要译出来供大家参考。   
    
  1.介绍:   
    
    防火墙的使用,有效的隔离了机构的内部网络和外部网络,这种类型的Internet架构变得越来越流行。这些防火墙系统大都充当着网络之间的应用层网关的角色,通常提供经过控制的Telnet,FTP,和SMTP访问。为了推动全球信息的交流,更多的新的应用层协议的推出。这就有必要提供一个总的架构使这些协议能够更明显和更安全的穿过防火墙。也就有必要在实际上为它们穿过防火墙提供一个更强的认证机制。这种需要源于客户机-服务器联系在不同组织网络之间的实现,而这种联系需要被控制和是很大程度上被认证的。   
    该协议被描述为用来提供在TCP和UDP域下为客户机-服务器应用程序便利和安全的穿过防火墙的一个架构。该协议在概念上被描述为一个介于应用层和传输层之间的"隔离层",但是这类服务并不提供网络层网关服务,如ICMP报文的传输。   
    
  2.现状:   
    
    SOCKS   4为基于TCP的客户机-服务器应用程序提供了一种不安全的穿越防火墙的机制,包括TELNET,FTP和当前最流行的信息发现协议如HTTP,WAIS和GOPHER.   
    新协议为了包括UDP扩展了SOCKS   4,为了包括对总体上更强的认证机制的支持扩展了协议架构,为了包括域名和IPv6地址的支持扩展了地址集。   
    SOCKS协议执行最具代表性的是包括了在SOCKS库中利用适当的封装程序来对基于TCP的客户程序进行重编译和重链结。   
    
  注意:   
    除非特别提及,封装在包格式中的十进制数表示的是通讯域的长度(用八位组octect表示)。一个给定的八位组必须具有指定的值,格式X'hh'被用来表示在该域中单个八位组的值。当单词"变量Variable"被使用时,它指出了通讯域拥有一个可变长度,这个可变长度要么由一个联合的(一个或两个八位组)长度域定义,要么由一个数据类型域所定义。   
    
  3.基于TCP客户机的程序   
    
    当一台基于TCP的客户机希望和目标主机建立连接时,而这台目标主机只有经过防火墙才能到达(这种情况?一直持续到?它被执行时),它就必须在 SOCKS服务器端的适当的SOCKS端口打开一个TCP连结。SOCKS服务按常例来说定位于TCP端口1080。如果连接请求成功,客户机为即将使用的认证方式进行一种协商,对所选的方式进行认证,然后发送一个转发请求。SOCKS服务器对该请求进行评估,并且决定是否建立所请求转发的连接。   
    客户机连接到服务器,发送一个版本标识/方法选择报文:   
    
    +----+----------+----------+   
    |VER   |   NMETHODS   |   METHODS   |   
    +----+----------+----------+   
    |   1 |     1  |   1   to   255   |   
    +----+----------+----------+   
    
    VER(版本)在这个协议版本中被设置为X'05'。NMETHODS(方法选择)中包含在METHODS(方法)中出现的方法标识八位组的数目。   
    服务器从METHODS给出的方法中选出一种,发送一个METHOD   selection(方法选择)报文:   
    
    +----+--------+   
    |VER   |   METHOD   |   
    +----+--------+   
    |   1 |    1  |   
    +----+--------+   
    
    如果所选择的METHOD的值是X'FF',则客户机所列出的方法是没有可以被接受的,客户机就必须关闭连接。   
    
  当前被定义的METHOD的值有:   
    >>   X'00'   无验证需求   
    >>   X'01'   通用安全服务应用程序接口(GSSAPI)   
    >>   X'02'   用户名/密码(USERNAME/PASSWORD)   
    >>   X'03'   至   X'7F'   IANA   分配(IANA   ASSIGNED)     
    >>   X'80'   至   X'FE'   私人方法保留(RESERVED   FOR   PRIVATE   METHODS)   
    >>   X'FF'   无可接受方法(NO   ACCEPTABLE   METHODS)   
  ***IANA是负责全球INTERNET上的IP地址进行编号分配的机构(译者著)***   
    于是客户机和服务器进入方法细节的子商议。方法选择子商议另外描述于独立的文档中。   
    欲得到该协议新的METHOD支持的开发者可以和IANA联系以求得到METHOD号。已分配号码的文档需要参考METHOD号码的当前列表和它们的通讯协议。   
    如果想顺利的执行则必须支持GSSAPI和支持用户名/密码(USERNAME/PASSWORD)认证方法。   
    
  4.需求   
    
    一旦方法选择子商议结束,客户机就发送请求细节。如果商议方法包括了完整性检查的目的和/或机密性封装,则请求必然被封在方法选择的封装中。   
    
  SOCKS请求如下表所示:   
    
    +----+-----+-------+------+----------+----------+   
    |VER   |   CMD   | RSV |   ATYP   |   DST.ADDR   |   DST.PORT   |   
    +----+-----+-------+------+----------+----------+   
    |   1 |    1   |   X'00'   |    1 |   Variable   |     2  |   
    +----+-----+-------+------+----------+----------+   
    
  其中:   
  o   VER   protocol   version:X'05'   
  o   CMD   
   o   CONNECT   X'01'   
   o   BIND   X'02'   
   o   UDP   ASSOCIATE   X'03'   
  o   RSV   RESERVED   
  o   ATYP   address   type   of   following   address   
   o   IP   V4   address:   X'01'   
   o   DOMAINNAME:   X'03'   
   o   IP   V6   address:   X'04'   
  o   DST.ADDR   desired   destination   address   
  o   DST.PORT   desired   destination   port   in   network   octet   order   
    
  5.地址   
    
    在地址域(DST.ADDR,BND.ADDR)中,ATYP域详细说明了包含在该域内部的地址类型:   
      o   X'01'   
    
    该地址是IPv4地址,长4个八位组。   
      o   X'03'   
    
    该地址包含一个完全的域名。第一个八位组包含了后面名称的八位组的数目,没有中止的空八位组。   
      o   X'04'   
    
    该地址是IPv6地址,长16个八位组。   
    
  6.回应   
    
    到SOCKS服务器的连接一经建立,客户机即发送SOCKS请求信息,并且完成认证商议。服务器评估请求,返回一个回应如下表所示:   
    
    
    +----+-----+-------+------+----------+----------+   
    |VER   |   REP   | RSV |   ATYP   |   BND.ADDR   |   BND.PORT   |   
    +----+-----+-------+------+----------+----------+   
    |   1 | 1 |   X'00'   | 1    |   Variable   |     2  |   
    +----+-----+-------+------+----------+----------+   
    
  其中:   
    
  o   VER   protocol   version:   X'05'   
  o   REP   Reply   field:   
    o   X'00'   succeeded   
    o   X'01'   general   SOCKS   server   failure   
    o   X'02'   connection   not   allowed   by   ruleset   
    o   X'03'   Network   unreachable   
    o   X'04'   Host   unreachable   
    o   X'05'   Connection   refused   
    o   X'06'   TTL   expired   
    o   X'07'   Command   not   supported   
    o   X'08'   Address   type   not   supported   
    o   X'09'   to   X'FF'   unassigned   
  o   RSV   RESERVED   
  o   ATYP   address   type   of   following   address   
    o   IP   V4   address:   X'01'   
    o   DOMAINNAME:   X'03'   
    o   IP   V6   address:   X'04'   
  o   BND.ADDR   server   bound   address   
  o   BND.PORT   server   bound   port   in   network   octet   order   
  标志RESERVED(RSV)的地方必须设置为X'00'。   
    
    如果被选中的方法包括有认证目的封装,完整性和/或机密性的检查,则回应就被封装在方法选择的封装套中。   
    
  CONNECT   
    
    在CONNECT的回应中,BND.PORT包括了服务器分配的连接到目标主机的端口号,同时BND.ADDR包含了关联的IP地址。此处所提供的 BND.ADDR通常情况不同于客户机连接到SOCKS服务器所用的IP地址,因为这些服务器提供的经常都是多址的(muti-homed)。都期望 SOCKS主机能使用DST.ADDR和DST.PORT,连接请求评估中的客户端源地址和端口。   
    
  BIND   
    
    BIND请求被用在那些需要客户机接受到服务器连接的协议中。FTP就是一个众所周知的例子,它通过使用命令和状态报告建立最基本的客户机-服务器连接,按照需要使用服务器-客户端连接来传输数据。(例如:ls,get,put)   
  都期望在使用应用协议的客户端在使用CONNECT建立首次连接之后仅仅使用BIND请求建立第二次连接。都期望SOCKS主机在评估BIND请求时能够使用DST.ADDR和DST.PORT。   
    有两次应答都是在BIND操作期间从SOCKS服务器发送到客户端的。第一次是发送在服务器创建和绑定一个新的socket之后。BIND.PORT 域包含了SOCKS主机分配和侦听一个接入连接的端口号。BND.ADDR域包含了关联的IP地址。  客户端具有代表性的是使用这些信息来通报应用程序连接到指定地址的服务器。第二次应答只是发生在预期的接入连接成功或者失败之后。在第二次应答中,BND.PORT和BND.ADDR域包含了欲连接主机的地址和端口号。   
    
  UDP   ASSOCIATE(连接?)   
    
    UDP   连接请求用来建立一个在UDP延迟过程中操作UDP数据报的连接。DST.ADDR和DST.PORT域包含了客户机期望在这个连接上用来发送UDP数据报的地址和端口。服务器可以利用该信息来限制至这个连接的访问。如果客户端在UDP连接时不持有信息,则客户端必须使用一个全零的端口号和地址。   
    
    当一个含有UDP连接请求到达的TCP连接中断时,UDP连接中断。   
    
    在UDP连接请求的回应中,BND.PORT和BND.ADDR域指明了客户端需要被发送UDP请求消息的端口号/地址。   
    
  回应过程   
    
    当一个回应(REP值非X'00')指明失败时,SOCKS主机必须在发送后马上中断该TCP连接。该过程时间必须为在侦测到引起失败的原因后不超过10秒。   
    如果回应代码(REP值为X'00')时,则标志成功,请求或是BIND或是CONNECT,客户机现在就可以传送数据了。如果所选择的认证方法支持完整性、认证机制和/或机密性的封装,则数据被方法选择封装包来进行封装。类似,当数据从客户机到达SOCKS主机时,主机必须使用恰当的认证方法来封装数据。   
    

       

 

 

sock5代理工作原理
出处:darkness fallen
时间:Wed, 26 Apr 2006 11:42:15 +0000
作者:hjma
地址:http://hjma.scgy.org/blog/bo-blog/read.php?3

内容:
sock5代理的工作程序是:

1。需要代理方向服务器发出请求信息。

2。代理方应答

3。需要代理方接到应答后发送向代理方发送目的ip和端口

4。代理方与目的连接

5。代理方将需要代理方发出的信息传到目的方,将目的方发出的信息传到需要代理方。代理完成

由于网上的信息传输都是运用tcp或udp进行的,所以使用socks5代理可以办到网上所能办到的一切,而且不舆目的方会查到你的ip,既安全又方便

sock5支持UDP和TCP,但两种代理是有区别的,以下分类说明

如何用代理TCP协议

1。向服务器的1080端口建立tcp连接。

2。向服务器发送 05 01 00 (此为16进制码,以下同)

3。如果接到 05 00 则是可以代理

4。发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)

5。接受服务器返回的自身地址和端口,连接完成

6。以后操作和直接与目的方进行TCP连接相同。

如何用代理UDP连接

1。向服务器的1080端口建立tcp连接

2。向服务器发送 05 01 00

3。如果接到 05 00 则是可以代理

4。发送 05 03 00 01 00 00 00 00 + 本地UDP端口(2字节)

5。服务器返回 05 00 00 01 +服务器地址+端口

7.需要申请方发送
00 00 00 01 +目的地址IP(4字节)+目的端口 +所要发送的信息

8。当有数据报返回时
向需要代理方发出00 00 00 01 +来源地址IP(4字节)+来源端口 +接受的信息

注:此为不需要密码的代理协议,只是socks5的一部分,完整协议请看RFC1928

附foxmail连接测试数据:
无sock5代理时TCP数据:
客户端 服务器
SYN
ACKSYN
ACK
+OK X1 NT-POP3 Server iflytek.com (IMail 8.15 230122-9)..
USER hjma..
+OK send your password..
PASS xxxxxxx..
+OK maildrop locked and ready..
STAT..
+OK 0 0..
QUIT..
+OK POP3 Server saying Good-Bye..
ACKFIN
ACK
ACKFIN
ACK

使用sock5代理时TCP数据:
客户端 sock5服务器
SYN
ACKSYN
ACK
05 01 00 00 00 00 
05 00 00 00 00 00
05 01 00 03 0E 31 39 32 2E 31 36 38 2E 37 35 2E 31 31 34 00 6E (.....192.168.75.114.n)
05 00 00 01 C0 A8 4D 56 08 D4
ACK
+OK X1 NT-POP3 Server iflytek.com (IMail 8.15 228888-9)..
USER hjma..
+OK send your password..
PASS xxxxxxx..
+OK maildrop locked and ready..
STAT..
+OK 0 0..
QUIT..
+OK POP3 Server saying Good-Bye..
ACKFIN
ACK
ACKFIN
ACK

 

 

 

sock代理分为sock4代理和 sock5代理。sock4支持TCP(事实仅支持TCP),无需用户名、密码验证;sock5支持TCP和UDP,根据代理服务器设置是否需要用户名、密码认证。TCP和UDP代理工作原理产不多,UDP代理网上多的是,google一下即可。这里只讲TCP代理工作原理。
sock代理工作原理大致如下:
1。需要代理方向服务器发出请求信息;
2。代理方应答;
3。需要代理方接到应答后发送向代理方发送目的ip和端口;
4。代理方与目的连接;
5。代理方将需要代理方发出的信息传到目的方,将目的方发出的信息传到需要代理方;
6。代理完成。
下面对sock4和sock5的代理工作原理流程分别详细说明,并给出示例代码。
sock4的TCP代理工作流程:
1。我们首先还是连接服务器,然后发送数据给服务器。由于是无用户密码验证,我们需要发送9个字节的数据,展开写为 04 01 + 目标端口(2字节) + 目标IP(4字节) + 00,其中目标端口和目标IP就是我们真正要连接的服务器端口和服务器地址;
2。代理服务器返回8字节的数据,我们只要判断第二字节是否为90即可,若是90连接成功,否则失败.剩下的操作和不存在代理服务器一样,可直接用发送/接受数据。
sock5的TCP代理工作流程:
1。向服务器的代理端口建立tcp连接。一般为1080;
2。向服务器发送 05 02 00 02(此为16进制码,以下同),让代理服务器选择认证方式 ;
05
02 这里确认2种认证方式 无需认证和需要认证,只需要验证一种方式,可以直接发送05 01 00查询服务器是否支持无认证代理方式;
00 不需要认证;
02 需要认证;
3。如果接到 05 00 则是可以代理或则05 02需要认证,这里只需要判断第二字节就行;
如果需要认证,需要向服务器发送01 用户名长度(2字节)用户名 密码长度(2字节)密码,然后接收服务器返回数据,如果第二字节为 00,则认证通过,否则无法认证,则连接失败;
4。发送 05 01 00 01 + 目的地址(4字节)+ 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)
5。接收代理服务器返回的数据,我们只要判断第二字节是否为00即表示代理连接完成;
6。以后操作和直接与目的方进行TCP连接相同。
   socks5代理和sock4代理都是很相似的(sock4代理网上应该有很多代码,我也曾在这里放过sock4代理的代理),不同的就是sock5代理除了支持UDP协议的数据外,还支持多种验证模式.一般常用的只是无验证模式(NO AUTHENTICATION )和用户/密码模式(USERNAME/PASSWORD),其它模式就算加上了,应用程序也不支持的(你可以看看oicq,msn,flashfxp等软件,也都只是支持这两种模式的).socks5代理一般是三种模式的支持,TCP CONNECT,TCP BIND和UDP ASSOCIATE,这里最常用的是TCP CONNECT,因为绝大部分TCP协议的软件都是使用这种模式的,TCP BIND只会用在FTP的Active模式中(就是数据连接是由FTP服务连接回FTP客户),并不常用,而且我测试过flashfxp和cuteftp,两种都不支持TCP BIND的(就是说如果是用了代理的话,两种软件都不支持使用Active模式,一定要使用Passive模式和FTP服务进行数据交换),所以我们只简单地讨论一下TCP CONNECT和UDP ASSOCIATE两种模式.
 Socks5代理的请求和返回信息.
1.客户端发送到socks5代理至少三个字节的请求,第一个字节一定为5,第二个字节为使用多少种验证,第三个字节为验证模式代码.
例:如果要使用"USERNAME/PASSWORD",那么这三个字节为5 1 2
2.Sock5代理接到上面请求后,如果是支持"USERNAME/PASSORD"的验证模式,就会返回两个字节,第一字节为5,第二字节为2.
3.客户端然后就向socks5代理发送验证信息,信息第一字节不需要理会,第二字节为验证用户名的长度,第三字节开始是用户名和密码信息.
4.socks5代理验证用户名和密码成功后,向客户端返回两个字节,5和0,如果验证失败,返回0x05和0xff.
5.客户端开始向sock5代理发送第一个向远程目标进行操作的请求,请求模式如下:
第一位为5
第二位是使用模式,0x01代表TCP CONNECT,0x02代表TCP BIND,0x03代表UDP ASSOCIATE
第三位保留
第四位是地址使用模式:0x01代表IP V4地址;0x03代表域名;0x04代表IP V6地址(一般常见的只是0x01和0x03两种模式,因为很多软件都不支持IP V6的)
第五位开始就是目标的地址和端口.
6.socks代理开始处理这个请求,对于TCP CONNECT和UDP ASSOCIATE模式有不同的处理.
A.对于TCP CONNECT
将请求分析后,将目标地址和 目标端口从请求中解析出来(无论请求中带的地址是否以域名方式发送过来,最终要将地址转换为IPV4的地址),然后使用connect()连接到目标地址中的目标端口中去,如果成功连接,那就向客户端发送回10个字节的信息,第一字节为5,第二字节为0,第三字节为0,第四字节为1,其它字节都为0.
B.对于UDP ASSOCIATE(这个复杂很多了)
将请求分析后,先保存好客户端的连接信息(客户端的IP和连接过来的源端口),然后本地创建一个UDP的socket,并将socket使用bind()绑入本地所有地址中的一个UDP端口中去,然后得到本地UDP绑定的IP和端口,创建一个10个字节的信息,返回给客户端去.第一字节为0x05,第二和第三字节都为0,第四字节为0x01(IPV4地址),第五位到第8位是UDP绑定的IP(以DWORD模式保存),第9位和第10位是UDP绑定的端口(以WORD模式保存).
7.最后是数据的传送了,TCP CONNECT和UDP ASSOCIATE模式又有所不同
A.对于TCP CONNECT
很简单,从客户中读到的所有数据,马上发送到远程目标;从远程目标中读到的所有数据,马上全部发送到客户端
B.对于UDP ASSOCIATE(又是复杂),
有数据包时,首先将数据全部读取,然后判断数据是从客户端还是远程目标传送过来的(在读取时可以得到是从什么地址和端口读取到数据的,然后比较上面第6步时我们保存了下来的客户端的连接信息),如果数据是从客户端读取过来的,我们要将UDP头去掉.例如我们读取到的Buffer,Buffer[3]是1时,UDP头就是10个字节长度,如果Buffer[3]是3的话,UDP头长度是7+Buffer[4].例如我们得到UDP头是20位,我们接收到的Buffer是50位长度,那么我们发送到目标的数据包长度是30位,前20位不发送,只发送后面的30位.如果数据是
从远程目标发送来的,我们就要多发送多10位的UDP头,这10位的UDP头前三位都是0,第四位是0x01,第五到第八位是我们保存下来的客户端的IP,第9和第十位是客户端的端口.如果我们接收到的Buffer长度是50,那么我们发送到客户端的数据就要加上10位的UDP头,也就是一共要发送60位字节长度的数据.
支持验证,支持TCP CONNECT和UDP ASSOCIATE模式的sock5代理的基本编写就是这样。
http://www.faqs.org/rfcs/rfc1928.html 是socks5代理的rfc,不过是写得非常非常简单的。我也有时会质疑rfc为什么都这么简单和模糊,为什么不可以写详细一点,或加上几个简单的例子。FTP服务的rfc甚至连列举文件时,ftp服务向客户发送回去的每一行信息的标准都没有,所以大家可以看到几乎每一个ftp服务向客户端返回的文件列表都不一定是相同的。
有一点需要补充的,那就是socks5代理的超时。在刚连接和验证那段期间可以设置超时,例如用户连接后30秒都没有验证的,就将那连接关闭。但验证后,就不可以设置超时了(或者是可以设置的,但我实在不知道如何做)。不可以设置超时的原因有两个:
1.对于UDP的连接,因为UDP是无连接的,你很难确定用户是否还是连接着,还会继续发送数据过来的。有人说可以定时发送数据过去。这是一种办法,但是要考虑到,因为你不知道用户是使用什么软件在发送UDP数据过来,你乱发数据过去,很大可能是被客户软件认为是不合法的数据而过滤掉,如果sock5代理因为发过去的数据被过滤了而认为客户 是断开了,那么极容易就将没有断开的用户也踢下去了,而且现在的oicq还会使用使用两个连接,一个是UDP连接,另一个是TCP连接,UDP连接只是登陆上服务器时使用,TCP连接却是进行数据传输的,而UDP连接却是一直都不会有数据传输的了,如果socks5代理因为UDP连接长时间没有数据传输而将那个UDP连接关闭的话,oicq也会因为这样而掉线(你关闭了UDP连接,oicq以为代理是不可用了,自己会将TCP连接断开)
2.对于TCP连接,设置超时是很简单,但只是对于一般只是使用一个连接进行数据通讯的软件有效,对于FTP是完全失效。当FTP客户挂socks5代理时,当有数据传输,例如列文件,下载文件或上传文件时,就会需要两个TCP连接,一个是接收FTP客户或接收FTP服务器返回的信息的,另一个是进行数据交换的,如果在进行长时间的数据交换时,例如上传文件或下载文件,有可能是要进行几小时或更长的数据交换,接收FTP客户命令或接收FTP服务器返回信息的那个TCP连接,是一直都没有数据通过的,如果设置了超时,例如1小时没有数据通过就断开连接的话,你就会将那个TCP连接关闭了,如果你关闭了那个TCP连接的话,FTP客户端也会马上将数据交换的那个TCP连接马上关闭(因为FTP客户端会认为自己被断开了)。
就因为这两点,我自己认为无法设置超时.也测试过几个socks5代理软件,也是没有在验证后做超时的处理的。因为TCP连接正常断开还是非正常的断开,socks5代理都可以轻易检查到,但UDP连接就很难检查,所以在测试中都有发现一些不正常断开的UDP连接还是一直没被socks5代理关闭到(ccproxy,wingate,还有大家可能最熟悉的skserver也是这样).




posted @ 2017-12-15 10:50  夜.__.风  阅读(1478)  评论(0编辑  收藏  举报