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和源端口都修改,后续步骤根据情况调整,但原理大致是一样的,这里不再赘述。
欢迎留言指导讨论!
NAT类型检测方案的更多相关文章
- STUN: NAT 类型检测方法
STUN(Simple Transversal of UDP through NATs)[21]是RFC3489 规定的一种NAT 穿透方式,它采用辅助的方法探测NAT 的IP 和端口. STUN 的 ...
- NAT类型与穿透 及 STUN TURN 协议
STUN : Simple Traversal of User Datagram Protocol [UDP] Through Network Address Translators [NATs] S ...
- Linux入侵痕迹检测方案【华为云技术分享】
背景说明 扫描是一切入侵的基础,通过扫描来发现目标主机是否为活动主机.操作系统是什么版本.开放了哪些服务等.扫描技术纷繁复杂,新的扫描技术也层出不穷,不可能穷举所有扫描技术,下面按入侵步骤对主机扫描. ...
- js类型检测总结
类型检测: 类和对象: Call,Apply,Bind
- javascript类型与类型检测
1.javascript类型: 注:包装对象:如"hello".length实际为js为我们隐式创建了一个String临时对象,去调用该对象的length属性,调用过后再将该临时对 ...
- 谈谈JavaScript类型检测
javascript内置的类型检测机制并非完全可靠.比如typeof操作符,并不能准确的判断数据是哪个类型,比如:数组和对象就不能通过typeof来区分. typeof [] ==="o ...
- JS数组类型检测
在强类型语言,数组类型检测是非常容易的事情(typeof就可以解决),而在弱语言JS数据类型就很容易混淆了. JS中常见的数据类型有:number.string.boolean.undefined.f ...
- 小结 javascript中的类型检测
先吐槽一下博客园的编辑器,太不好用了,一旦粘贴个表格进来就会卡死,每次都要用html编辑器写,不爽! 关于javascript的类型检测,早在实习的时候就应该总结,一直拖到现在,当时因为这个问题还出了 ...
- Objective-C 【动态类型检测&响应方法】
------------------------------------------- 动态类型检测 代码: #import <Foundation/Foundation.h> @inte ...
- [C++]C++中的运行时类型检测
Date:2014-1-3 Summary: 使用C++中的运行时类型检测.(文章重点在于记录本人的使用情况,并非深层讨论RTTI) Contents:写习惯C#的我,在C++依然存在哪些.NET的惯 ...
随机推荐
- Notion API中Internal Notion integrations和Public Notion integrations的区别
Internal Notion integrations Internal Notion integrations与一个单一的.特定的工作区相联系,只有该工作区的成员可以使用这个integration ...
- python交教程4:文件操作
文件操作流程 人类操作一个word流程: 1.找到文件.双击打开 2. 读或修改 3. 保存&关闭 ⽤python操作⽂件也差不多: 只读模式 创建模式 追加模式 遍历文件 图片视频- ...
- 保障升级:Splashtop 公布安全顾问委员会成员
加利福尼亚州圣何塞,2020年12月17日-远程访问和远程支持解决方案的全球领导者 Splashtop Inc. 召集了网络安全性和合规性方面的领先专家,成立了该公司的安全顾问委员会.这组顾问有助于指 ...
- pageoffice6 实现提取数据区域为子文件(Word拆分)
在实际的开发过程中,有时会遇到希望提取Word文档中部分内容保存为子文件的需求,PageOffice支持提取Word文档数据区域中的内容为一个Word文件流,在服务器端创建PageOffice的Wor ...
- 让智慧物联赋能高效生产, AIRIOT助力数字化油田转型升级
近年来,中国石油行业为了推进工业化和信息化深度融合,充分结合勘探开发.生产科研和经营管理的实际需求,积极通过信息化建设促进油田业务转型升级.在勘探开发与管理的领域中,油气生产物联网系统是一个极其重 ...
- CMD文件内容统计程序简单版本
WordCount命令行程序通过CMD接收参数,输出统计结果到指定文件. 项目码云地址:https://gitee.com/ggtc/WordCount.git 实现的功能有: 统计文件字符数 1 u ...
- JS监听DOM创建和销毁
源码 web开发指南 <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&quo ...
- 一套完整的中小级别的企业级监控prometheus
一 相信有很多博客都已经详细的说明了prometheus的作用以及相关的作用以及原理,这里不在赘述,仅仅从部署和配置2个方面来记录一下,为公司产品组搭建的prometheus告警平台的过程以及踩过 ...
- Spring 对 Junit4,Junit5 的支持上的运用
1. Spring 对 Junit4,Junit5 的支持上的运用 @ 目录 1. Spring 对 Junit4,Junit5 的支持上的运用 每博一文案 2. Spring对Junit4 的支持 ...
- 自定义Naive UI的数据表格Data Table中按钮Button图标
在Naive UI官网中详细介绍了[数据表格 Data Table](数据表格 Data Table - Naive UI)的使用方式 { title: "Action", key ...