NAT(NAPT)机制及应用
UDP/TCP的差异
TCP的模拟
模拟TCP的现实意义
本章内容分为三部分:
NAT(NAPT)
机制及应用TCP
协议的特性- 使用
UDP
模拟TCP
实现TCP
协议中的主要特性
NAT(NATP)
我们已经学习过UDP
与TCP
协议(伯克利socket
接口函数)的使用,无论是sendto
还是send
,我们的目标IP地址都是公网IP,而不是局域网IP(本机通信或者局域网通信除外)。
当我们想要将流量发送到公网(广域网)上时,目标IP地址必须是公网IP。
以上是网络编程的基础常识。
那么,为什么我主机上的钉钉能够能跟你主机上的钉钉通信呢?我们两台主机都在不同的局域网中,都位于网关(路由器)后面。
似乎道理也很简单,因为钉钉服务器的存在,我们不过是将消息发送给了钉钉的公网服务器,然后服务器进行了转发。那么,一台网关设备后面有若干台主机,每台主机上都有钉钉,那网关是怎么准确无误的指导需要将钉钉消息发送到哪台主机呢?
最关键的问题是,我们的局域网IP地址192.168.0.1
怎么就能与一个局域网后面的192.168.0.2
主机通信呢?服务器的存在?为啥公网服务器就能与局域网IP通信呢?
要回答这个问题,就要知道,NAT
机制。
为了缓解IP地址的紧张,现在网关都具备NAT
功能,能够只通过一个公网IP地址就能让N台主机与外界通信。
NAT
的全称是Network Address Translation
网络地址转换。
局域网地址之所以能访问远程公网服务器的原因在于在网关(路由器)设备中,有一个nat
模块专门用来处理局域网地址与公网地址的映射关系:
真的的秘密在于每台主机的流量到达网关后,其内网IP地址以及端口都会被改写。
改写为这个网关的外网IP地址和一个新的端口号因此内网IP:端口1
与外网IP:端口2
形成了一个1对1的新映射,这个映射的组成元素一共有4个,任何一个元素不同都是一条新的映射。
其实注意到,并不是简单的内网IP与外网IP组成一条映射,还包括端口这一元素,因此NAT
又被称为NAPT
(P = Port)
因此,真实的通信就变成了这样子:
NAT还未形成一个标准方案,不同的设备厂商都有自己的实现,不过大致说了现行的NAT有4种不同的类型:
- 完全圆锥形NAT类型
- 受限圆锥形NAT类型
- 端口受限圆锥形NAT类型
- 对称NAT类型
从名字上看不出任何端倪,甚至有些莫名其妙。
当主机通过网关(路由器)访问远程服务器server-1时,流量经过网关前往server-1服务器时,便会建立一个NAT映射,将内部地址LocalIP:LocalPort
映射到了外部地址WideIP:WidePort
,此时通过WideIP:WidePort
这个点就能访问server-1服务器,而server-1也能讲流量发送到WideIP:WidePort
这个点,然后通过查NAT映射关系,网关将流量转发到局域网主机上。不仅如此,即使之前没有与主机通信过的server-2服务器此时也能直接通过WideIP:WidePort
将流量发送到局域网内部主机,即server-2也能直接与局域网主机通信,而这一切得益于NAT表映射关系的建立。
映射建立完成后,对目标主机的IP和端口都无限制,的这种类型,就是所谓的完全圆锥形NAT类型
主机LocalIP:LocalPort
访问server-1时,NAT设备会创建一个NAT表映射,得到一个WideIP:WidePort
,通过这个地址访问主机server-1,此后server-1就能通过NAT设备将流量传输给主机了,与上面(完全圆锥形NAT类型)类型不同的是,此时server-2不能通过这个WideIP:WidePort
访问主机,而必须要是内部主机先与外部主机通信,然后外部主机才能将流量传输给内部主机。比如内部主机通过LocalIP:LocalPort
先访问了server-3后,此时server-3才能访问内部主机(通过NAT设备)。
而对外部主机的地址要求是theWideHostIP:AnyPort
。必须要是已经通过信的那个外部主机IP,而对外部主机的端口,不做要求。
映射建立完成后,对目标主机的IP有限定,对目标主机端口无限制,的这种类型,就是所谓的受限圆锥形NAT类型
当在『受限圆锥形NAT类型』的基础上加一个端口限制后,就成了第三种NAT类型,即所谓的『端口受限圆锥形NAT类型』
这意味着,只有主机先与外部server通信后,外部server才能与主机通信,并且前提还有,并不是只要外部主机IP地址符合要求就好,还必须要求外部主机的端口也不能变,如图:
而最后一种类型就是『对称NAT』,这种类型的限制最多。
只有先当内部主机访问外部主机(服务器)后,外部主机(服务器)才能访问内部主机,并且,只能沿着原路返回数据,也就是说,通过网关设备出去的外部地址都是一个唯一的点,通过这个点,只能访问一对IP:端口
号(注意,不是说只能访问一台主机)
到目前为止,我们已经讨论完了NAT的4种类型,路由器就是一个NAT设备。那么有个这个知识储备后,有什么用呢?
主机之间的通信
C-S
模型的架构是非常经典的并且占据互联网大部分流量的一种模型,几乎我们常说的网络编程就是在使用C-S
架构(及其变种)
这是经典的C-S
通信架构,通过公网服务器,每一个客户端都能访问到这台服务器,而无论客户端是否位于NAT后面(是否处于局域网中),这种设计的好处是明显的:
- 保证两台主机之间肯定可以进行通信
- 让两台主机实现通信的逻辑变得简单
- 很多时候业务逻辑并不要求两台主机进行通信,而是服务器只作为资源的提供者,这种模式下
C-S
架构天生适合
以上都是这种架构的优势。但这种架构并不适合所有场景(其实,没有任何一种架构能包治百病),比如即时聊天软件直接的通信就是主机与主机的通信了,那么在需要端与端的通信时,C-S
模式的架构就不是最优的了(只是从技术上讲,不从政策上讲。因为政策上而言,服务器必须介入主机与主机的通信,用来保存通信内容供government查阅,这种情况下必须C-S
架构,而某些主打隐私安全的设计就不是采用这种架构)
我们对C-S-C
模式能够理解,但是我们需要讨论下p2p(peer to peer)可行的理由。(这部分只是在我们实际工作中可能不会使用上,但是对理解掌握网络的完整性是个必不可少的一部分,甚至日后理解所谓的反射、隧道等都大有裨益)
根据图示,两台NAT之间的流量是可以直达的,但这是否意味这局域网主机1和局域网主机2就能因此而流量直达了呢?
答案是肯定的,但是还有几个问题要解决:
- 主机需要知道自己的公网IP地址(端口)。
- 主机需要让另一台主机知道自己的公网IP地址(端口),且,自己也需要知道对方的。
那么,怎么解决呢?
引入一个公网服务器,完美解决以上2个问题。
这个服务器通常被称为『打洞服务器』,这个『洞』就是给NAT挖了个洞,让流量可以穿透过去。那么这个打洞服务器做了几个什么事情呢?
- 识别局域网主机1和局域网主机2的外网地址以及端口
- 相互交换对方的外网地址(端口)信息
这样,局域网主机1里的相关进程就知道了局域网主机2的外网地址(端口),反之同理。这样局域网主机1 、2里的某个相关进程都掌握了对方的外网地址(端口)。
那这样是不是就意味着局域网主机1、2能直接通信了呢?
答案是不一定。
回顾我们上面讨论的NAT的4种类型,会发现一种NAT类型是绝对无法打洞成功的。在此之前,我们来理一下正常情况下,是如何打洞的,步骤是什么。
1、主机A访问打洞服务器
2、主机B访问打洞服务器
3、打洞服务器交换两个主机的外网地址信息(端口)
4、主机A访问B的外网地址,此时NAT会记录B的外网地址,当流量到达主机B的NAT设备后,因为NAT设备『不认识』(没记录过A主机,也不知道这个流量要转发给那个主机),所以直接丢弃这个包,数据并不会到主机B,但是,此时B主机的NAT设备会记录A的外网地址。
5、此时,打洞服务器会通知主机B,让B主机马上把流量发送到主机A的外网地址,此时因为在第4步时主机A的NAT设备记录了主机B的外网信息,因此主机A的NAT设备会让主机B的流量通过,并且会把B的流量准确的转发给主机A。
6、此时,主机A会马上访问主机B的外网地址,因为在第4步时,主机B的NAT设备记录了主机A的外网地址,同时在第5步时也记录了主机B要访问主机A的外网地址的信息,因此,主机B的NAT设备会让主机A的流量通过,并且准确的转发到主机B上
经过以上6步,就能建立主机A与主机B之间的端到端的通信了。
至此事情似乎都很完美,但是回头看看我们上面所说的NAT类型的第四个,也就是『对称NAT类型』,在这种类型的NAT面前,此路不通了。我们来推演一下:
当此时NAT类型是第4中类型(对称NAT)时:
1、主机A访问打洞服务器;NAT-A设备记录映射(192.168.0.1:5566
:43.250.201.20:6789
),远程服务器记录A的外网地址为43.250.201.20:6789
2、主机B访问打洞服务器;NAT-B设备记录映射(192.168.0.2:7788
:113.250.201.20:4567
),远程服务器记录B的外网地址为113.250.201.20:4567
3、交换2个外网地址信息
4、主机A访问B的外网地址,113.250.201.20:4567
,NAT直接拒绝,并且不会留下任何记录。理由很简单,这个外网地址建立的访问路径是本机地址
-外网IP:端口1
-打洞服务器地址
,流量只能在这条路径上传输,打洞服务器能与外网IP:端口1
通信,但是当别的外网地址访问这个B的地址时,直接被拒。也就是说在对称NAT的类型中,本机地址
-NAT外网地址
-远程外网地址
三者构成了独一无二的通信链路,其他节点无法加入。
需要再三说明的是,这里的地址是指IP地址:端口号
这一对组合。
有NAT设备的地方,就有NAT类型。因此两端其实有10种两两组合的情况。
我们不能简单的说端口受限型NAT可以打洞,对称型NAT不能打洞,而是要看双方的组合是什么。
比如 对称型-对称型,这就是不能打洞的。而如果是受限锥型-对称型则可能可以。
那么,用来打洞的通常是UDP流量,还是TCP流量呢?答案是UDP流量。
答案很简单,并非TCP不行,而是用TCP打洞太难太难,操作手法复杂,而用UDP则相对简单很多。
为什么?
回想一下打洞过程:
主机A的某进程需要通过socket
访问打洞服务器,为了让主机端口固定,使用bind
,将某个固定端口绑定到本机,此后又要创建一个socket
访问远程主机B,使用TCP
无法创建2个本机IP和绑定端口一致的socket
。
而UDP
就没有这样的问题。
这算是『非面向链接』协议的一点点『好处』吧。
远程控制既可以通过C-S
模式实现,或者p2p
模式实现,至于那种方案更优,相信大家有自己的判断。(在p2p的打洞中,如果打不通,会切换成C-S
模式)。当然,C-S
的实现模型更简单,而NAT是可以嵌套的,因此情况会更复杂。
以上,就是有关NAT
的相关内容。
posted on 2021-12-28 09:36 shadow_fan 阅读(1398) 评论(0) 编辑 收藏 举报