一、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和源端口都修改,后续步骤根据情况调整,但原理大致是一样的,这里不再赘述。

欢迎留言指导讨论!

NAT类型检测方案的更多相关文章

  1. STUN: NAT 类型检测方法

    STUN(Simple Transversal of UDP through NATs)[21]是RFC3489 规定的一种NAT 穿透方式,它采用辅助的方法探测NAT 的IP 和端口. STUN 的 ...

  2. NAT类型与穿透 及 STUN TURN 协议

    STUN : Simple Traversal of User Datagram Protocol [UDP] Through Network Address Translators [NATs] S ...

  3. Linux入侵痕迹检测方案【华为云技术分享】

    背景说明 扫描是一切入侵的基础,通过扫描来发现目标主机是否为活动主机.操作系统是什么版本.开放了哪些服务等.扫描技术纷繁复杂,新的扫描技术也层出不穷,不可能穷举所有扫描技术,下面按入侵步骤对主机扫描. ...

  4. js类型检测总结

    类型检测: 类和对象: Call,Apply,Bind

  5. javascript类型与类型检测

    1.javascript类型: 注:包装对象:如"hello".length实际为js为我们隐式创建了一个String临时对象,去调用该对象的length属性,调用过后再将该临时对 ...

  6. 谈谈JavaScript类型检测

      javascript内置的类型检测机制并非完全可靠.比如typeof操作符,并不能准确的判断数据是哪个类型,比如:数组和对象就不能通过typeof来区分. typeof [] ==="o ...

  7. JS数组类型检测

    在强类型语言,数组类型检测是非常容易的事情(typeof就可以解决),而在弱语言JS数据类型就很容易混淆了. JS中常见的数据类型有:number.string.boolean.undefined.f ...

  8. 小结 javascript中的类型检测

    先吐槽一下博客园的编辑器,太不好用了,一旦粘贴个表格进来就会卡死,每次都要用html编辑器写,不爽! 关于javascript的类型检测,早在实习的时候就应该总结,一直拖到现在,当时因为这个问题还出了 ...

  9. Objective-C 【动态类型检测&响应方法】

    ------------------------------------------- 动态类型检测 代码: #import <Foundation/Foundation.h> @inte ...

  10. [C++]C++中的运行时类型检测

    Date:2014-1-3 Summary: 使用C++中的运行时类型检测.(文章重点在于记录本人的使用情况,并非深层讨论RTTI) Contents:写习惯C#的我,在C++依然存在哪些.NET的惯 ...

随机推荐

  1. Notion API中Internal Notion integrations和Public Notion integrations的区别

    Internal Notion integrations Internal Notion integrations与一个单一的.特定的工作区相联系,只有该工作区的成员可以使用这个integration ...

  2. python交教程4:文件操作

    文件操作流程 人类操作一个word流程: 1.找到文件.双击打开 2. 读或修改 3. 保存&关闭 ⽤python操作⽂件也差不多: 只读模式  创建模式  追加模式  遍历文件  图片视频- ...

  3. 保障升级:Splashtop 公布安全顾问委员会成员

    加利福尼亚州圣何塞,2020年12月17日-远程访问和远程支持解决方案的全球领导者 Splashtop Inc. 召集了网络安全性和合规性方面的领先专家,成立了该公司的安全顾问委员会.这组顾问有助于指 ...

  4. pageoffice6 实现提取数据区域为子文件(Word拆分)

    在实际的开发过程中,有时会遇到希望提取Word文档中部分内容保存为子文件的需求,PageOffice支持提取Word文档数据区域中的内容为一个Word文件流,在服务器端创建PageOffice的Wor ...

  5. 让智慧物联赋能高效生产, AIRIOT助力数字化油田转型升级

    ​ 近年来,中国石油行业为了推进工业化和信息化深度融合,充分结合勘探开发.生产科研和经营管理的实际需求,积极通过信息化建设促进油田业务转型升级.在勘探开发与管理的领域中,油气生产物联网系统是一个极其重 ...

  6. CMD文件内容统计程序简单版本

    WordCount命令行程序通过CMD接收参数,输出统计结果到指定文件. 项目码云地址:https://gitee.com/ggtc/WordCount.git 实现的功能有: 统计文件字符数 1 u ...

  7. JS监听DOM创建和销毁

    源码 web开发指南 <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&quo ...

  8. 一套完整的中小级别的企业级监控prometheus

    一   相信有很多博客都已经详细的说明了prometheus的作用以及相关的作用以及原理,这里不在赘述,仅仅从部署和配置2个方面来记录一下,为公司产品组搭建的prometheus告警平台的过程以及踩过 ...

  9. Spring 对 Junit4,Junit5 的支持上的运用

    1. Spring 对 Junit4,Junit5 的支持上的运用 @ 目录 1. Spring 对 Junit4,Junit5 的支持上的运用 每博一文案 2. Spring对Junit4 的支持 ...

  10. 自定义Naive UI的数据表格Data Table中按钮Button图标

    在Naive UI官网中详细介绍了[数据表格 Data Table](数据表格 Data Table - Naive UI)的使用方式 { title: "Action", key ...