NAT类型检测方案
一、NAT分类
NAT大致有4种类型:
1. Full Cone NAT
完全锥形NAT,所有从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号,并且任何一个外网主机都可以通过这个映射的外网IP和端口号向这台内网主机发送包。
2. Restricted Cone NAT
限制锥形NAT,它也是所有从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号。与完全锥形不同的是,外网主机只能够向先前已经向它发送过数据包的内网主机发送包。
3. Port Restricted Cone NAT
端口限制锥形NAT,与限制锥形NAT很相似,只不过它包括端口号。也就是说,一台IP地址X和端口P的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个IP地址X和端口P发送过数据包。
4. Symmetric NAT
对称NAT,所有从同一个内网IP和端口号发送到一个特定的目的IP和端口号的请求,都会被映射到同一个IP和端口号。如果同一台主机使用相同的源地址和端口号发送包,但是发往不同的目的地,NAT将会使用不同的映射。此外,只有收到数据的外网主机才可以反过来向内网主机发送包。
我们知道,使用五元组可以定位一条流,分别是源端口(SPORT),源IP(SIP),协议(Protocol,如TCP/UDP等),目的端口(DPORT),目的地址(DIP)。
不同类型的NAT,其实就是在做NAT哈希以及匹配时使用和检查的五元组数据不同。
上述4种NAT分类的区别如下(假设协议为UDP):
NAT类型 | NAT哈希使用的信息 | NAT匹配检查的信息(针对回应报文) | 备注 |
完全锥形NAT | SIP,SPORT |
映射后的IP和端口号 |
由于在NAT哈希时只使用了SIP和SPORT,若SIP和SPORT一样,都会映射成同一个IP和端口(无论DIP和DPORT是否一样)。 这3类NAT的区别就在于对回应报文的检测方式不同。
假设有3台外网主机A,B,C。内网主机使用相同的源IP和源端口向主机A和B发送报文,映射后的IP和端口都是一样的。
针对完全锥形NAT,外网主机A,B,C可以使用任何源端口向映射的IP和端口发送报文,报文都会被送达内网主机;
针对限制锥形NAT,外网主机A,B可以使用任何源端口向映射的IP和端口发送报文,主机C发送的报文会被丢弃 (由于内网主机没有向主机C发送过报文,无法通过源IP检查);
针对端口限制锥形NAT,外网主机A,B只能使用指定源端口(内网主机报文的目的端口)向映射的IP和端口发送报文, 若使用其它端口作为源端口,则报文会被丢弃(无法通过源端口检查)。主机C发送的报文会被丢弃 (由于内网主机没有向主机C发送过报文,无法通过源IP和源端口检查); |
限制锥形NAT |
映射后的IP和端口号 回应报文的源IP |
||
端口限制锥形NAT |
映射后的IP和端口号 回应报文的源IP和源端口 |
||
对称NAT | SIP,SPORT,Protocol,DPORT,DIP |
映射后的IP和端口号 回应报文的源IP和源端口 |
对称NAT对回应报文的检查和端口限制锥形NAT一样,区别在于做NAT哈希时使用的信息。五元组内任意一个元组发生变化,则映射后的IP或端口都会发生变化。 |
二、NAT类型检查
了解了NAT的分类后,可以设计一个NAT类型检查的方式。
此方式要求至少有2台外网服务器,分别为主机A和B。
流程如下:
步骤1:内网主机发送一个UDP报文给A,其中源端口为13357,目的端口为6000,源IP为内网主机的私网地址,目的IP为外网主机A的地址。
此报文(在负载中指定)要求服务器使用映射后的IP和端口作为目的IP和目的端口进行回应,源IP和源端口与报文的目的IP和端口相同,并在回应中包含映射后的IP和端口信息。
这个回应报文肯定能被收到,除非网络不通。
收到此报文后,通过报文中包含的映射后的IP和端口信息,内网主机可以做如下判断:
1,映射后的IP和端口与内网主机地址和源端口一样。可以判断主机位于公网,没有NAT。流程结束。
2,映射后的IP和端口与内网主机地址和源端口不一样。则可以判断主机位于内网,到公网之间有NAT设备。(当然,这里不一样有3种情况,即1,仅地址不一样;2,仅端口不一样;3,地址和端口都不一样;一般是第3种情况。第1种情况也有可能,因为NAT的哈希算法计算后的映射端口可能与源端口恰好一样。第2种情况属于异常场景,暂不考虑。)
步骤2:内网主机发送一个UDP报文给A,其中源端口为13357,目的端口为6000,源IP为内网主机的私网地址,目的IP为外网主机A的地址。(与步骤1发送的报文的信息一样)
此报文(在负载中指定)要求服务器使用映射后的IP和端口作为目的IP和目的端口进行回应,源IP与报文的目的IP相同,但修改源端口为其它端口(与上行报文的目的端口不一样),并在回应中包含映射后的IP和端口信息。
根据NAT类型的不同,内网主机不一定能够收到此回应报文。
1,收到此回应报文。
可以判断NAT类型为完全锥形NAT(类型1)或限制锥形NAT(类型2)。因为根据另外两种NAT的定义,不可能收到这种回应报文。
当然,也可以对负载再次进行检查,期望负载中包含的映射后的IP和端口与第一个回应一样,若不一样,则属于异常情况,暂不考虑。
2,未收到回应报文。
可以判断NAT类型为端口限制锥形NAT(类型3)或对称NAT(类型4)。因为根据另外两种NAT的定义,肯定会收到这种回应报文。(暂时不考虑丢包的情况。实际实现时,可以通过重传此报文来解决可能的丢包场景。)
步骤3:此步骤要根据步骤2的情况来进行。分两种情况。
1,步骤2中收到了回应报文。
此时再次发送一个与步骤1和2中类似的报文,IP头部信息不变,但在负载中携带信息要求服务器A通知服务器B,让服务器B来给内网主机发送回应。(服务器A和服务器B之间的交互不在本文的范围内)。
若收到此回应,则表明NAT类型是完全锥形NAT(类型1),否则就是限制锥形NAT(类型2)。因为限制锥形NAT会检查源IP,服务器B发送的回应由于使用了不同的源IP,不能通过此检查。
到此流程结束。
2,步骤2中未收到回应报文。
此时需要在端口限制锥形NAT(类型3)或对称NAT(类型4)中做判断。
与步骤1类似,内网主机给服务器B发送一个报文,并检查回应中携带的映射后的IP和端口信息。
若与步骤1中回应的一样,则表明是端口限制锥形NAT(类型3),否则就是对称NAT(类型4)。
至此,一个简易的NAT类型检测流程就完成了。
上述流程中,没有考虑丢包,异常处理等。需要在实现时完善。
另外,UDP报文中携带的信息,可以参考RFC3489/5389/5766这3篇文档,利用里面定义的消息类型和选项,包括使用事务ID来匹配请求和回应等。
重传机制,如超时时间,重传次数等,都需要在实现时考虑。
本文是在研究了比特彗星(Bitcomet)的NAT类型发现功能后写出的。只是一个猜想,跟比特彗星或其它商业软件的实现大概率不一致。
另外,上述步骤中,步骤2的回应报文修改了源端口,当然也可以直接修改源IP,甚至源IP和源端口都修改,后续步骤根据情况调整,但原理大致是一样的,这里不再赘述。
欢迎留言指导讨论!