现在P2P技术中讨论的最热门的话题,我想怕是如何在不通过中转服务器的情况下,如何畅通无阻的传递文件了(当然,广泛的说法是传递信息),本人并非这方面的专家,也还没有完全找到“畅通无阻的传递文件”的灵丹妙药,这个问题的确是很棘手,因为即使现在最具有代表性的JXTA,在PEER之间传递信息也不能完全的达到这个要求,也要通过Rendezvous Peer(集合点) 或RouterPeer(路由Peer) ,GatewayPeer(网关Peer)等来协助中转--当然,JXTA秉承了JINI的先进思想和特性,在现在的网络环境下,我想这应该是最理想不过的P2P设计(在另外一个话题中,我会比较详细和大家探讨一下)。至于MSN,QQ,ICQ等,我想是典型的集中式服务器的代表,就没多少讨论的必要了!
我这里想讨论的,是在不依靠专门的中转服务器,而在网关(或者说连到外部网络的出口)上装有SOCKS代理服务器的情况下,可以突破双重(多重?!)SOCKS代理服务器的封锁来传递信息的一点个人小技巧,因为在我在公布可以突破双重(多重?!)SOCKS代理服务器的封锁来传递信息这个观点后,许多人都表示怀疑,甚至有少数人说根本不可能,当然,更多的是希望把这个技巧说一下。对于IT技术来说,这是非常正常的一种现象,我在这里公布的目的并非是“你不信,我让你看看”,因为我DEMO已经发布出来,其实勤快一点的人只要试一下,就知道真和假了,所以我无意于为这种目的来费这么多唇舌!我只是希望在这里和大家交流一下,权做抛砖引玉,希望大家共同进步!
废话少说(不然有人抛烂西红柿了,^_^)还不明白SOCKS代理协议的人先到Http://www.china-pub.com/computers/eMook/emooknew/rfctxt/RFC1928.txt冲一下电,不明白基本TCP/IP协议的也请先了解一下,不然会听的不知所云!
突破双重SOCKS代理服务器的封锁来传递文件,简单来说,就是假设有这么一种网络情况,PeerA1(对等机A1) 在A局域网内,通过PeerA连接到互连网络上,PeerA上安装了SOCKS代理服务器, PeerB1(对等机B1) 在B局域网内,通过PeerB连接到互连网络上,PeerB上安装了SOCKS代理服务器,如下所示:
------------------------------------------------------
PeerA1 (192.168.0.3) <局域网内IP>
|
|
(192.168.0.1) <局域网网关IP>-安装了SOCKS代理服务器
PeerA
[202.15.2.199]
|
|
(internet)
|
|
[68.124.5.128]
PeerB
(192.168.0.1) <局域网网关IP>-安装了SOCKS代理服务器
|
|
PeerB1(192.168.0.3) <局域网内IP>
-----------------------------------------------------
现在,假如两台机器能通过SOCKET套节字直接建立连接的话,我开发的软件已经可以传递文件了(因为PeerA禁止了所有的进出端口,就只留1080,我要访问外部资源的话,只能通过代理服务器了),并且速度还不错呢,你看你看,电影《黑客帝国3》正从PeerA1欢快的跑到PeerB呢!
可是, 我希望从PeerA1传递一个文件到PeerB1,该怎么办呢,众所周知,PeerA1和PeerB1处在不同的局域网后面,并且没有公网IP,通过SOCKET套节字直接通信(TCP/IP协议)是没办法的(或许有办法,不过我不知道,你知道吗)!
天无绝人之路,既然两个网关上都装有SOCKS代理服务器,那或许有希望,那到底怎么做,我才能达到目的呢?
噢,先来看看SOCKS代理协议吧http://www.china-pub.com/computers/eMook/emooknew/rfctxt/RFC1928.txt:
这个协议说:
-----------------------------------------------------
3.基于TCP协议的客户
当一个基于TCP协议的客户端希望与一个只能通过防火墙可以到达的目标(这是由实现所决定
的)建立连接,它必须先建立一个与SOCKS服务器上SOCKS端口的TCP连接。通常这个TCP端口是
1080。当连接建立后,客户端进入协议的“握手(negotiation)”过程:认证方式的选择,根据选
中的方式进行认证,然后发送转发的要求。SOCKS服务器检查这个要求,根据结果,或建立合适的
连接,或拒绝。
除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某
域需要给定一个字节的值,用X'hh'来表示这个字节中的值。如果某域中用到单
词'Variable',这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1 – 2个
字节)的域中,或一个数据类型域中。
客户端连到服务器后,然后就发送请求来协商版本和认证方法:
VER
NMETHODS
METHODS
1
1
1 to 255
这个版本的SOCKS协议中,VER字段被设置成X'05'。NMETHODS字段包含了在METHODS字段中
出现的方法标示的数目(以字节为单位)。
服务器从这些给定的方法中选择一个并发送一个方法选中的消息回客户端:
VER
METHOD
1
1
如果选中的消息是X'FF',这表示客户端所列出的方法列表中没有一个方法被选中,客户端
必须关闭连接。
当前定义的方法有:
? X'00' 不需要认证
? X'01' GSSAPI
? X'02' 用户名/密码
? X'03' -- X'7F' 由IANA分配
? X'80' -- X'FE' 为私人方法所保留的
? X'FF' 没有可以接受的方法
然后客户和服务器进入由选定认证方法所决定的子协商过程(sub-negotiation)。各种不同的
方法的子协商过程的描述请参考各自的备忘录。
开发者如果要为自己的方法得到一个方法号,可以联系IANA。可以参考关于已经被分配号码
的文档以得到当前所有方法的列表和相应的协议。
符合本文档的SOCKS V5实现必须支持GSSAPI,并且在将来支持用户名/密码认证方式。
4.请求
一旦子协商过程结束后,客户端就发送详细的请求信息。如果协商的方法中有以完整性检查和
/或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。
SOCKS请求的格式如下:
VER
CMD
RSV
ATYP
DST.ADDR
DST.PORT
1
1
X'00'
1
Variable
2
其中
? VER 协议版本: X'05'
? CMD
? CONNECT:X'01'
? BIND:X'02'
? UDP ASSOCIATE:X'03'
? RSV 保留
? ATYP 后面的地址类型
? IPV4:X'01'
? 域名:X'03'
? IPV6:X'04''
? DST.ADDR 目的地址
? DST.PORT 以网络字节顺序出现的端口号
SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。
5.地址
ATYP字段中描述了地址字段(DST.ADDR,BND.ADDR)所包含的地址类型:
? X'01'
基于IPV4的IP地址,4个字节长
? X'03'
基于域名的地址,地址字段中的第一字节是以字节为单位的该域名的长度,没有结尾的NUL字
节。
? X'04'
基于IPV6的IP地址,16个字节长
6.应答
一旦建立了一个到SOCKS服务器的连接,并且完成了认证方式的协商过程,客户机将会发送一
个SOCKS请求信息给服务器。服务器将会根据请求,以如下格式返回:
VER
REP
RSV
ATYP
BND.ADDR
BND.PORT
1
1
X'00'
1
Variable
2
其中:
? VER 协议版本: X'05'
? REP 应答字段:
? X'00' 成功
? X'01' 普通的SOCKS服务器请求失败
? X'02' 现有的规则不允许的连接
? X'03' 网络不可达
? X'04' 主机不可达
? X'05' 连接被拒
? X'06' TTL超时
? X'07' 不支持的命令
? X'08' 不支持的地址类型
? X'09' – X'FF' 未定义
? RSV 保留
? ATYP 后面的地址类型
? IPV4:X'01'
? 域名:X'03'
? IPV6:X'04'
? BND.ADDR 服务器绑定的地址
? BND.PORT 以网络字节顺序表示的服务器绑定的段口
标识为RSV的字段必须设为X'00'。
如果选中的方法中有以完整性检查和/或安全性为目的的封装,这些应答必须按照该方法所定
义的方式进行封装。
CONNECT
在对一个CONNECT命令的应答中,BND.PORT包含了服务器分配的用来连到目标机的端口号,
BND.ADDR则是相应的IP地址。由于SOCKS服务器通常有多个IP,应答中的BND.ADDR常和客户端
连到SOCKS服务器的那个IP不同。
SOCKS服务器可以利用DST.ADDR和DST.PORT,以及客户端源地址和端口来对一个CONNECT请
求进行分析。
BIND
BIND请求通常被用在那些要求客户端接受来自服务器的连接的协议上。FTP是一个典型的例
子。它建立一个从客户端到服务器端的连接来执行命令以及接收状态的报告,而使用另一个从服务
器到客户端的连接来接收传输数据的要求(如LS,GET,PUT)。
建议只有在一个应用协议的客户端在使用CONNECT命令建立主连接后才可以使用BIND命令建
立第二个连接。建议SOCKS服务器使用DST.ADDR和DST.PORT来评价BIND请求。
在一个BIND请求的操作过程中,SOCKS服务器要发送两个应答给客户端。当服务器建立并绑
定一个新的套接口时发送第一个应答。BND.PORT字段包含SOCKS服务器用来监听进入的连接的端
口号,BAND.ADDR字段包含了对应的IP地址。客户端通常使用这些信息来告诉(通过主连接或控
制连接)应用服务器连接的汇接点。第二个应答仅发生在所期望到来的连接成功或失败之后。在第
二个应答中,BND.PORT和BND.ADDR字段包含了连上来的主机的IP地址和端口号。
UDP ASSOCIATE
UDP ASSOCIATE请求通常是要求建立一个UDP转发进程来控制到来的UDP数据报。DST.ADDR和
DST.PORT 字段包含客户端所希望的用来发送UDP数据报的IP地址和端口号。服务器可以使用这个
信息来限制进入的连接。如果客户端在发送这个请求时没有地址和端口信息,客户端必须用全0来
填充。
当与UDP相应的TCP连接中断时,该UDP连接也必须中断。
应答UDP ASSOCIATE请求时,BND.PORT 和BND.ADDR字段指明了客户发送UDP消息至服务器的
端口和地址。
应答处理
当一个应答(REP值不等于00)指明出错时,SOCKS服务器必须在发送完应答消息后一小段时间
内终止TCP连接。这段时间应该在发现错误后少于10秒。
如果一个应答(REP值等于00)指明成功,并且请求是一个BIND或CONNECT时,客户端就可以
开始发送数据了。如果协商的认证方法中有以完整性、认证和/或安全性为目的的封装,这些请求
必须按照该方法所定义的方式进行封装。类似的,当以客户机为目的地的数据到达SOCKS服务器
时,SOCKS服务器必须用正在使用的方法对这些数据进行封装。
-----------------------------------------------------
看到了吧,我刚才的就是通过这个握手过程来建立从PeerA1到PeerB的连接的,总之,只要照这个协议,即使通过代理服务器也能建立从PeerA1到PeerB的连接了!
什么什么,我要的是怎么从PeerA1传文件到PeerB1呢,从PeerA1到PeerB我八百年前就会了!
别急,仔细观察一下这个握手过程,
1 发送请求来协商版本和认证方法:05 01 00 (无密码验证请求,若密码验证请求,则发05 02 00 00),然后等待返回;
2 若成功,则MOTHED返回为00,然后“然后客户和服务器进入由选定认证方法所决定的子协商过程(sub-negotiation)。”
3 现在假设子协商已经完成并且成功,OTHED返回为00,则“一旦子协商过程结束后,客户端就发送详细的请求信息”,现在,假设我们发送“详细的请求信息”为:05 01 00 01 <目标地址><目标端口>(CONNECT方式)
4 若成功,则下面就可以开始正常的数据传输了
好,现在我们知道了正常的SOCKS握手过程了,可是, 这和我们的问题有什么关系呢?
思考中。。。
既然我可以通过这个握手过程来和PeerA上的代理服务器建立关系,那么我可不可以在通过PeerA后,不要直接去连接PeerB1(连也连不通,因为找不到啊),再和PeerB上的代理服务器来一次握手呢,假如和PeerB能够再一次握手成功,那不是就解决我们的问题了吗。。。。
事不宜迟,马上再看看上面的握手过程。。。。
1 发送请求来协商版本和认证方法。。。。看,想,看,想,再看,再想。。。没法下手,不经过第一次的握手,下面就别想走通
2 进入由选定认证方法所决定的子协商过程。。。。看,想,看,想,再看,再想。。。没法下手,和PeerA的握手还没完呢,下面别想走通
3 “一旦子协商过程结束后,客户端就发送详细的请求信息”。。。。看,想,看,想,再看,再想。。。哦,协商好象完成了,是不是该在这里下手了。。。。假如我现在继续发送第一步的数据到PEERB上的代理服务器,是不是可以呢。。。。。但是,就不符合正常SOCKS的握手协议的第三步了。。。。假如第一步发送的请求数据可以和第三步发送的请求数据一样的话。。。。第一步,05 01 00。。。第三步,05 01 00 01 <地址><端口>(CONNECT方式)。。。。有点相同呢。。。那我现在把05 01 00 01 <目标地址><目标端口>(CONNECT方式)改为05 01 00 01 <PEERB的地址><PEERB的SOCKS服务端口>(CONNECT方式)。。。发送。。。哦,返回00呢,继续子协商。。。。哦,返回00呢。。。再发送05 01 00 01 <地址><端口>(CONNECT方式)。。。。啊,我的PeerB1上的程序有反映了,@#$%&*@#$%^&%^&^&%%*&*$$#@###$%%^^^&^&%$##....
阳光多美妙啊,世界真奇妙,太阳从西边出来了。。。我在做倒立呢。。。
下面实验的事情就是大家的工作了,现在,
B2盖次起立,请问,假如我的网络结构变成了如下结构,你该怎么做:
------------------------------------------------------
PeerA1 (192.168.0.3) <局域网内IP>
|
|
(192.168.0.1) <局域网网关IP>-安装了SOCKS代理服务器
PeerA
[202.15.2.199]
|
|
(internet)
|
|
PeerC
[66.124.88.128] <局域网网关IP>-安装了SOCKS代理服务器
|
|
PeerD
[66.124.89.128] <局域网网关IP>-安装了SOCKS代理服务器
|
|
PeerE
[66.124.98.128] <局域网网关IP>-安装了SOCKS代理服务器
|
|
PeerF
[66.124.88.120] <局域网网关IP>-安装了SOCKS代理服务器
|
|
[68.124.5.128]
PeerB
(192.168.0.1) <局域网网关IP>-安装了SOCKS代理服务器
|
|
PeerB1(192.168.0.3) <局域网内IP>
-----------------------------------------------------
SOCKS代理协议制定小组组长起立,请问,经过我的的一番实验,假如PEERB的代理服务器需要验证,为什么这个方法就不管用了,我不管啊,要不就改改你们的这个协议,让PEERB的代理服务器需要验证时,我也可以用这个办法。。。。。。……—…………·%……—*%%%%%%%%%%(呵呵,对不起了,老前辈们,开个玩笑呢)
演示DEMO:http://systemer.51.net