原文版权:Copyright (C) The Internet Society (2003).All Rights Reserved.
原文地址:http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt
译文版权申明:请引用此文的作者或网站注明出处:http://blog.csdn.net/hxhbluestar,以尊重译者的劳动成果!
注:在看这篇文章之前,读者需要了解TCP的基础知识,了解TCP建立连接的基本步骤
3.5. Simultaneous TCP open 同时开放TCP连接
There is a method that can be used in some cases to establish direct peer-to-peer TCP connections between a pair of nodes that are both behind existing middleboxes. Most TCP sessions start with one endpoint sending a SYN packet, to which the other party responds with a SYN-ACK packet. It is possible and legal, however, for two endpoints to start a TCP session by simultaneously sending each other SYN packets, to which each party subsequently responds with a separate ACK. This procedure is known as a "simultaneous open."
这里有一种方法能够在某种情况下建立一个穿透NAT的端对端TCP直连。我们知道,绝大多数的TCP会话的建立,都是通过一端先发送一个SYN包开始,另一方则回发一个SYN-ACK包的过程。然而,这里确实存在另外一种情况,就是P2P的双方各自同时地发出一个SYN包到对方的公网地址上,然后各自都单独地返回一个ACK响应来建立一个TCP会话,这个过程被称之为:“Simultaneous open”(“同时开放连接”)。
If a middlebox receives a TCP SYN packet from outside the private network attempting to initiate an incoming TCP connection, the middlebox will normally reject the connection attempt by either dropping the SYN packet or sending back a TCP RST (connection reset) packet. If, however, the SYN packet arrives with source and destination addresses and port numbers that correspond to a TCP session that the middlebox believes is already active, then the middlebox will allow the packet to pass through. In particular, if the middlebox has just recently seen and transmitted an outgoing SYN packet with the same addresses and port numbers, then it will consider the session active and allow the incoming SYN through.
If clients A and B can each correctly predict the public port number that its respective middlebox will assign the next outgoing TCP connection, and if each client initiates an outgoing TCP connection with the other client timed so that each client's outgoing SYN passes through its local middlebox before either SYN reaches the opposite middlebox, then a working peer-to-peer TCP connection will result.
如果一个NAT接收到一个来自私有网络外面的 TCP SYN 包,这个包想发起一个“引入”的 TCP 连接,一般来说,NAT会拒绝这个连接请求并扔掉这个SYN 包,或者回送一个TCP RST(connection reset,重建连接)包给请求方。但是,有一种情况,当这个接收到的 SYN 包 中的源IP地址和端口、目标IP地址和端口都与NAT登记的一个已经激活的TCP会话中的地址信息相符时,NAT将会放行这个SYN 包,让它进入NAT内部。特别要指出,如果NAT恰好看到一个刚刚发送出去的一个SYN包也和上面接收到的SYN包中的地址信息相符合的话,那么NAT将会认为这个TCP连接已经被激活,并将允许这个方向的SYN包进入NAT内部。
如果 Client A 和 Client B 能够彼此正确的预知对方的NAT将会给下一个TCP连接分配的公网TCP端口,并且两个客户端能够同时地发起一个“外出”的TCP连接,并在对方的 SYN 包到达之前,自己刚发送出去的SYN包都能顺利的穿过自己的NAT的话,一条端对端的TCP连接就成功地建立了。
(好似一个间谍活动)
Unfortunately, this trick may be even more fragile and timing-sensitive than the UDP port number prediction trick described above. First, unless both middleboxes are simple firewalls or implement cone NAT behavior on their TCP traffic, all the same things can go wrong with each side's attempt to predict the public port numbers that the respective NATs will assign to the new sessions. In addition, if either client's SYN arrives at the opposite middlebox too quickly, then the remote middlebox may reject the SYN with a RST packet, causing the local middlebox in turn to close the new session and make future SYN retransmission attempts using the same port numbers futile. Finally, even though support for simultaneous open is technically a mandatory part of the TCP specification [TCP], it is not implemented correctly in some common operating systems. For this reason, this trick is likewise mentioned here only for historical reasons; it is NOT recommended for use by applications. Applications that require efficient, direct peer-to-peer communication over existing NATs should use UDP.
不幸的是,这个诡计比3.4节所讲的UDP端口预言更容易被粉碎,并且对时间的敏感性的依赖更多!首先,除非双方的NAT都是Simple firewalls 或者都像cone NAT那样处理TCP通信,否则两个客户端还是无法建立这个TCP直连,因为它们无法预知对方的NAT会分配给新的会话的端口号是多少。 另外,如果双方的 SYN 到达对方的NAT 速度太快(举例来说,就是SYN A的还未穿过NAT A时,SYN B已经提早到达了NAT A),对方的NAT会将这个SYN扔掉,并返回一个 RST 包,这样就使得这个发快了的一方NAT关闭原来的会话,又重新建立一个新的会话,再利用这个新的会话重发一个SYN,这时端口预言就失效了,因为再次分配到相同的端口地址的几率太小了。
最后,尽管在“TCP规范”中说明了“Simultaneous open”是一种支持的标准技术,但是在一些公共操作系统中,对这种技术的支持并不好。基于这个原因,我们也在这里郑重申明,并不推荐使用这个技术。如果您的应用程序想要穿透NAT并进行高效率高性能的P2P的通信,应该使用UDP技术!
这里我将这个技术的详细过程描述如下,欢迎大家指正:
过程详细描述:
Client A发送一个TCP SYN 包给 Client B,我们把这个SYN包叫做 SYN A,包含的信息如下:
SrcAddress:10.0.0.1 Tcp port :1234
DestAddress:138.76.29.7 Tcp port:310000
同时,Client B发送一个TCP SYN包给Client A,我们把这个包叫做 SYN B,包含的信息如下:
SrcAddress:10.1.1.3 Tcp port :1234
DestAddress:155.99.25.11 Tcp port:620000
SYN A首先通过NAT A(必须在SYN B到达NAT A之前),NAT A看到这个包并将其地址信息进行转换为:
SrcAddress:155.99.25.11 Tcp port :620000
DestAddress:138.76.29.7 Tcp port:310000
我们把这个经过 NAT A转换的包叫做 SYN A’
同样,SYN B首先通过NAT B(也必须在SYN A到达NAT B之前),NAT B看到这个包并进行地址转换为:
SrcAddress:138.76.29.7 Tcp port:310000
DestAddress:155.99.25.11 Tcp port :620000
我们把这个经过NAT B转换的包叫做 SYN B’
这时,NAT A和NAT B都在自己的TCP连接表中存储了含有上面两个公网IP地址和端口信息,因此,只要看到包含这两个信息的SYN包,都会让其通过。
就在这个瞬间,SYN A’到达了NAT B,NAT B检查了一下SYN A’,发现它的地址信息和自己TCP连接表中的信息相符,便让SYN A’通过了,并将SYN A’的地址信息转换为:我们称这个包为 SYN A’’
SrcAddress:155.99.25.11 Tcp port :620000
DestAddress:10.1.1.3 Tcp port:1234
以使这个包能够到达内部网中Client B上
也就在这个瞬间,SYN B’到达了NAT A,NAT A检查了一下SYN B’,发现它的地址信息和自己TCP连接表中的信息相符,便让SYN B’通过了,并将SYN B’的地址信息转换为:我们称这个包为 SYN B’’
SrcAddress:138.76.29.7 Tcp port :310000
DestAddress:10.0.0.1 Tcp port:1234
以使这个包能够到达内部网中Client A上
这时,Client A收到了SYN B’’,Client B收到了SYN A’’,并返回给对方ACK,经过三次握手,这个P2P的TCP连接就建立了。