NAT是在传输层及以上做的,传输层最主要的2个协议是TCP和UDP。对于TCP和UDP而言,每个包都有很基本的4个要素:src ip、src port、dst ip、dst port。
根据在做NAT的时候是否保留src ip和src port,可以把NAT分为这么三种:
Cone: 将src ip映射到一个固定的IP,并且将src port映射到一个固定的Port,无论dst ip和dst port是什么。
Single IP address, symmetric:将src ip映射到一个固定的IP,将src port映射到一个随机的port,但是保证对于相同的(dst ip,dst port), src port始终相同。(否则双方没法通话啊,回来的包回给哪个端口呢?)
Multiple IP address, symmetric:与上面类似,但是src ip可能会有多个。
这三种之中,最简单的就是Cone。根据对incoming packet的过滤限制,可能把Cone分为3种:
Full Cone: A full cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Furthermore, any external host can send a packet to the internal host, by sending a packet to the mapped external address. 这种NAT通常被称为static NAT,比如拿iptables redirect作端口转发。
Restricted Cone: A restricted cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Unlike a full cone NAT, an external host (with IP address X) can send a packet to the internal host only if the internal host had previously sent a packet to IP address X.这种就是当有连接的时候,洞才打开。只限制IP,通讯的另一方,可以用任意端口。
Port Restricted Cone: A port restricted cone NAT is like a restricted cone NAT, but the restriction includes port numbers. Specifically, an external host can send a packet, with source IP address X and source port P, to the internal host only if the internal host had previously sent a packet to IP address X and port P. 既限制IP又限制端口。
对于Cone,可采用很简单的NAT穿透的方式建立P2P直连。
RTMFP中的P2P打洞过程:
假设一共三个角色:Server、Initiator(Peer1)、Target(Peer2)。Peer2已经与Server建立RTMFP连接,现在Peer1要连接Peer2。
Peer1首先向Server发InitiatorHello请求,其中带上Peer2的peerID。Peer1此时并不知道Peer2的地址,它只知道PeerID。
Server向Peer1回复一个Redirect消息,里面包含Peer2的公网IP端口(通过UDP包头可以得到)、以及Peer2的所有内网IP端口(Peer2自己可以得知,它在建立完和Server的连接后会通过SetPeerInfo汇报给Server)。
稍等一小会儿(1秒左右),Server给Peer2回复一个Forward Message,里面包含Peer1的公网IP端口。
RTMFP Redirect消息就像HTTP的302一样,收到者(Peer1)需要向新地址重新建立连接,即发送InitiatorHello包。RTMFP Redirect消息中是一个IP端口的列表,每个IP端口都要去尝试。
Forward Message就像servlet里面的forward一样,收到者(Peer2)需要直接给原始的请求者回包(回Response Hello)。
对Peer1来说,哪个地址先回给它第一个Response Hello包,它就跟哪个地址继续握手。
假设Peer1和Peer2处于同一个NAT中,那么会尽量通过redirect消息进行直连,以后的交互就跟NAT没有关系。
假设Peer1和Peer2处于不同的NAT之中,两个NAT类型都是Port Restricted Cone,那么Peer1收到Redirect消息的时候,然后向Peer2发送InitiatorHello的时候,就在Peer1的NAT上打了一个洞。虽然这个InitiatorHello也许会被Peer2的防火墙拦掉,但是没有关系,正因为有了这个洞,Peer2的ResponseHello才能进来。
假设Peer1是处于symmetric single IP NAT之后,那么Server给Peer2的地址其实是一个错误的地址(端口号不对),所以Peer2收到Forward消息后所作的那个ResponseHello包,Peer1根本就收不到。但是假如Peer2是Restricted Cone,发完这个ResponseHello之后它就能接收来自Peer1的任何端口包。所以它们能接着Redirect消息之后的流程继续走下去。
如果很不幸,Peer2也是处于symmetric single IP NAT之后,那么Peer2在回复Forward消息的时候就要采用猜端口的方式,给Peer1多发几个ResponseHello包,如果有幸猜中了Peer1答复Redirect消息时所采用的端口,那么两者就可以连接起来了。不过Flash好像没有这么做。
NAT检查工具:http://cc.rtmfp.net/
Public UDP port number same as local UDP port number:这个是指NAT是否将src port做了转换。
Can receive from same IP address, same UDP port number:这个值应当永远是Yes。因为如果连这个检查都通不过,连接根本就建立不起来。
Can receive from same IP address, different UDP port number:如果这个值是true,说明是Port Restricted Cone,它会把出去的包的dst port记录下来,然后收到包时检查port number。
Can receive from different IP address, different UDP port number:如果这个值是true,说明是Restricted Cone,即它不对端口号做检查。
Can send to different IP address after server introduction:这个值应当永远是Yes。
Source IP address is preserved from original connection:这个是看server收到的包是否都来自于同一个IP。这个有一定的假阳性在里面,只要有一次为false,就说明用的是Multiple IP address symmetric NAT。
Source UDP port number is preserved from original connection:true说明是cone NAT,false说明是symmetric NAT。
我自制了一张连通性图:
Restricted Cone | Port Restricted Cone | symmetric single IP | symmetric multiple IP | |
Restricted Cone | Yes | Yes | Yes | No |
Port Restricted Cone | Yes | Yes | No | No |
symmetric single IP | Yes | No | No | No |
symmetric multiple IP | No | No | No | No |