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的惯 ...
随机推荐
- 一个可一键生成短视频的AI大模型,亲测可用
大家好,我是 Java陈序员. 自从 OpenAI 发布 Sora 文本生成视频模型后,文本生成视频的 AI 技术引起了无数圈内圈外人士的关注和实验. 今天,给大家介绍一个大模型,可一键生成短视频. ...
- 微服务从代码到k8s部署应有尽有系列全集
微服务从代码到k8s部署应有尽有系列全集 https://mp.weixin.qq.com/s/8U2h85YJHy3H3hzlBakPPw 实战项目地址:https://github.com/Mik ...
- Linux查看文件指定行数内容与查找文件内容
Linux查看文件指定行数内容 1.tail date.log 输出文件末尾的内容,默认10行 tail -20 date.log 输出最后20行的内容 tail -n -20 date.log 输出 ...
- JavaScript 数组常用方法整理
数组变异方法 push() 数组末尾添加一个项目,返回新数组长度,arr.push(item)pop() 数组末尾删除一个元素,返回被删除元素,arr.pop()shift() 删除数组开头第1个元素 ...
- C语言:将txt文件的单词导入链表&&删除链表重复单词
文章目录 前言 主要分为两个实现部分,按个人需求浏览 首先明确几个任务 先过一遍如何操作的流程. ①全局变量和结构体代码部分 ②实现:将文件单词导入链表 a: 寻找txt文件中最长单词的函数 b: 导 ...
- Laravel 实现自定义资源路由
Laravel 如何实现自定义资源路由 最近在开发过程中,发现总有一些路由需要重复定义,比如切换状态,导出,回收站啊之类的.如果使用 Laravel 自带的资源路由方法,还不足以满足重复劳动得过程.所 ...
- 【数字基座·智慧物联】AIRIOT新品发布会在京举办
2023年6月6日,由航天科技控股集团股份有限公司主办的"数字基座·智慧物联"AIRIOT新品发布会在北京成功举办,重磅发布了AIRIOT 4.0物联网平台的五大核心能力引擎,并邀 ...
- Gin 框架是怎么使用 net http 包的(gin.go)
Gin 框架是基于 Go 语言的标准库 net/http 构建的,它使用 net/http 提供的基础功能来构建自己的高性能 Web 应用框架. 具体来说,Gin 使用 net/http 的以下方面: ...
- 使用node压缩js
先下载并安装Node 安装完成后打开cmd运行:node -v 运行:npm -v 确定node安装成功,然后安装uglifyjs,打开cmd输入下面命令: npm install uglify-js ...
- 腾讯蓝鲸平台部署v5.1版本[去坑]
腾讯蓝鲸平台部署 1. 环境准备 #1. 基础优化 ulimit -SHn 655360 yum remove mysql-devel -y && yum install mysql- ...