yjjnls/Notes

View on GitHub
media/NAT.md

Summary

Maintainability
Test Coverage

- [NAT](#nat)
    - [一对多的NAT](#%E4%B8%80%E5%AF%B9%E5%A4%9A%E7%9A%84nat)
        - [按照NAT端口映射方式分类](#%E6%8C%89%E7%85%A7nat%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84%E6%96%B9%E5%BC%8F%E5%88%86%E7%B1%BB)
            - [全锥形NAT](#%E5%85%A8%E9%94%A5%E5%BD%A2nat)
            - [限制锥形NAT](#%E9%99%90%E5%88%B6%E9%94%A5%E5%BD%A2nat)
            - [端口限制锥形NAT](#%E7%AB%AF%E5%8F%A3%E9%99%90%E5%88%B6%E9%94%A5%E5%BD%A2nat)
            - [对称型NAT](#%E5%AF%B9%E7%A7%B0%E5%9E%8Bnat)
    - [NAT的弊端](#nat%E7%9A%84%E5%BC%8A%E7%AB%AF)
    - [NAT穿越](#nat%E7%A9%BF%E8%B6%8A)
        - [通信双方只有一方位于NAT后(反向链接)](#%E9%80%9A%E4%BF%A1%E5%8F%8C%E6%96%B9%E5%8F%AA%E6%9C%89%E4%B8%80%E6%96%B9%E4%BD%8D%E4%BA%8Enat%E5%90%8E%EF%BC%88%E5%8F%8D%E5%90%91%E9%93%BE%E6%8E%A5%EF%BC%89)
        - [通信双方都位于NAT设备之后,且进行基于UDP应用的通信(UDP打洞技术)](#%E9%80%9A%E4%BF%A1%E5%8F%8C%E6%96%B9%E9%83%BD%E4%BD%8D%E4%BA%8Enat%E8%AE%BE%E5%A4%87%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%B8%94%E8%BF%9B%E8%A1%8C%E5%9F%BA%E4%BA%8Eudp%E5%BA%94%E7%94%A8%E7%9A%84%E9%80%9A%E4%BF%A1%EF%BC%88udp%E6%89%93%E6%B4%9E%E6%8A%80%E6%9C%AF%EF%BC%89)
            - [普通p2p实现过程](#%E6%99%AE%E9%80%9Ap2p%E5%AE%9E%E7%8E%B0%E8%BF%87%E7%A8%8B)
        - [STUN方式的P2P实现](#stun%E6%96%B9%E5%BC%8F%E7%9A%84p2p%E5%AE%9E%E7%8E%B0)

# NAT
NAT(Network Address Translation,网络地址转换)简单来说就是为了`解决IPV4下的IP地址匮乏`和`保护网内主机`而出现的一种技术。  
NAT通常部署在一个组织的网络出口位置,替换IP报文头部的地址信息。在报文离开私网进入Internet时,将源IP替换为公网地址,通常是出口设备的接口地址。一个对外的访问请求在到达目标以后,表现为由本组织出口设备发起,因此被请求的服务端可将响应由Internet发回出口网关。出口网关再将目的地址替换为私网的源主机地址,发回内部。

*  双向流量必须都要经过NAT网关
*  网络访问只能先由私网侧发起,公网无法主动访问私网主机
*  NAT网关为了实现双向翻译的功能,需要维护一张关联表,把会话的信息保存下来


## 一对多的NAT
当有多个内部主机去访问同一个服务器时,从返回的信息不足以区分响应应该转发到哪个内部主机。   
此时,需要NAT设备根据传输层信息或其他上层协议去区分不同的会话,并且可能要对上层协议的标识进行转换,比如TCP或UDP端口号。   


### 按照NAT端口映射方式分类
#### 全锥形NAT
其特点为:一旦内部主机端口对(iAddr:iPort)被NAT网关映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);`任何一个外部主机`发送到(eAddr:ePort)的报文将会被转换后发到(iAddr:iPort)。

#### 限制锥形NAT
其特点为:一旦内部主机端口对(iAddr:iPort)被映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);只有 (iAddr:iPort)向特定的外部主机hAddr`发送过数据`,**主机hAddr从`任意端口`**发送到(eAddr:ePort)的报文将会被转发到(iAddr:iPort)。

#### 端口限制锥形NAT
其特点为:一旦内部主机端口对(iAddr:iPort)被映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);只有(iAddr:iPort)向特定的外部主机端口对(hAddr:hPort)`发送过数据`,`由 (hAddr:hPort)发送`到(eAddr:ePort)的报文将会被转发到(iAddr:iPort)。

#### 对称型NAT
其特点为:NAT网关会把内部主机“地址端口对”和外部主机“地址端口对”完全相同的报文看作一个连接,在网关上创建一个**公网“地址端口对”映射**进行转换,**只有收到报文的外部主机从对应的端口对发送回应的报文,才能被转换**。即使内部主机使用之前用过的地址端口对去连接不同外部主机(或端口)时,NAT网关也会建立新的映射关系。

## NAT的弊端
*  NAT使IP会话的保持时效变短。因为一个会话建立后会在NAT设备上建立一个关联表,在会话静默的这段时间,NAT网关会进行老化操作。
*  NAT工作机制依赖于修改IP包头的信息,这会妨碍一些安全协议的工作。因为NAT篡改了IP地址、传输层端口号和校验和,这会导致认证协议彻底不能工作,因为认证目的就是要保证这些信息在传输过程中没有变化。
*  NAT在实现上将多个内部主机发出的连接复用到一个IP上,这就使依赖IP进行主机跟踪的机制都失效了

在P2P的应用中,一个用户的主机既为下载的客户,同时也向其他客户提供数据,是一种C/S混合的模型。上层应用之所以能这样设计,是因为IP协议栈定义了这样的能力。试想一下,`如果IP提供的能力不对等,那么每个通信会话都只能是单方向发起的,这会极大限制通信的能力`。**NAT最大的弊端正在于此——破坏了IP端到端通信的能力。**当采用P2P之中连接方式的时候,NAT会阻止外网地址的访问,这时我们就得采用NAT穿透了。



## NAT穿越
NAT穿越的本质就是为了消除NAT的弊端,使得端到端之间能够直接通信。  

* 应用层网关
* 探针技术STUN和TURN
* 中间件技术
* 中继代理技术
* 特定协议的自穿越技术

### 通信双方只有一方位于NAT后(反向链接)
这种情况下,ClientA在NAT后,ClientB和server位于公网,通过server的中转,ClientB可以知道ClientA的公网地址,但是无法直接发给A。这里可以是B通过server给A发一个连接请求,A收到连接请求后反向主动连接B(tcp),这样在NAT上就会建立相关表项,A和B就能实现端到端的通信。

### 通信双方都位于NAT设备之后,且进行基于UDP应用的通信(UDP打洞技术)
#### 普通p2p实现过程
1.  首先,Client A登录服务器,NAT A为这次的Session分配了一个端口60000,那么Server S收到的Client A的地址是`202.187.45.3:60000`,这就是Client A的外网地址了。
2.  同样,Client B登录Server S,NAT B给此次Session分配的端口是40000,那么Server S收到的B的地址是`187.34.1.56:40000`。
3.  此时Client A与Client B都可以与Server S通信了。
4.  如果Client A此时想直接发送信息给Client B,
    那么他可以从Server S那儿获得B的公网地址187.34.1.56:40000,
    **是不是Client A向这个地址发送信息Client B就能收到了呢?**
    **答案是不行**,因为如果这样发送信息,NAT B会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。
5.  现在需要的是在NAT B上打一个方向为`202.187.45.3`(即Client A的外网地址)的洞,那么Client A发送到187.34.1.56:40000的信息,Client B就能收到了。这个打洞命令由谁来发呢?自然是Server S。

**此方法只适合锥型NAT,对于对称型NAT,则是行不通的。**因为当Client B向Client A打洞的端口已经重新分配了,Client B将无法知道这个端口,还有其他很多因素。

上述过程基本可以简化为通过中间服务器server能够使AB双方获得对方的NAT公网地址。但是要实现通信,还要设计两个部分。一个是`探测各自的NAT类型`,如果是对称型NAT,那基本没戏;第二是`打洞`。  
UDP打洞技术是通过中间服务器的协助在各自的NAT网关上建立相关的表项,使P2P连接的双方发送的报文能够直接穿透对方的NAT网关,从而实现P2P客户端互连。

*  用户A先通过服务器知道用户B的外网地址与端口 
*  用户A向用户B的外网地址与端口发送消息, 
*  在这一次发送中,用户B的网关会拒收这条消息,因为它的映射中并没有这条规则。 
*  但是用户A的网关就会增加了一条允许规则,允许接收从B发送过来的消息 
*  服务器要求用户B发送一个消息到用户A的外网IP与端口号 
*  用户B发送一条消息,这时用户A就可以接收到B的消息,而且网关B也增加了允许规则 
*  之后,由于网关A与网关B都增加了允许规则,所以A与B都可以向对方的外网IP和端口号发送消息

### STUN方式的P2P实现
客户端通过STUN服务器得到自己的NAT类型和公网IP、Port。

ref   
https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API/Protocols
https://www.cnblogs.com/imstudy/p/5458133.html
http://blog.csdn.net/fireroll/article/details/51913258