本文已参与「新人创作礼」活动.一起开启掘金创作之路。
在我们真实的网络环境中,NAT 随处可见,而它的出现主要是出于两个目的。第一个是解决 IPv4 地址不够用的问题。在 IPv6 短期内无法替换 IPv4 的情况下,如何能解决 IP 地址不够的问题呢?人们想到的办法是,让多台主机共用一个公网 IP 地址,然后在内部使用内网 IP 进行通信,这种方式大大减缓了 IPv4 地址不够用的问题。第二个是解决安全问题,也就是主机隐藏在内网,外面有 NAT 挡着,这样的话黑客就很难获取到该主机在公网的 IP 地址和端口,从而达到防护的作用。
不过凡事有利也有弊,NAT 的引入确实带来了好处,但同时也带来了坏处。如果没有 NAT,那么每台主机都可以有一个自己的公网 IP 地址,这样每台主机之间都可以相互连接。可以想象一下,如果是那种情况的话,互联网是不是会更加繁荣?因为有了公网 IP 地址后,大大降低了端与端之间网络连接的复杂度,我们也不用再费这么大力气在这里讲 NAT 穿越的原理了。
如果从哲学的角度来讲,“世上的麻烦都是自己找的”,这句话还是蛮有道理的。
在WebRTC处理过程中,NAT所处的位置
NAT 的种类
随着人们对 NAT 使用的深入,NAT 的设置也越来越复杂。尤其是各种安全的需要,对 NAT 的复杂性起到了推波助澜的作用。经过大量研究,现在 NAT 基本上可以总结成 4 种类型:完全锥型、IP 限制锥型、端口限制锥型和对称型。
1. 完全锥型 NAT
完全锥型 NAT 的特点是,当 host 主机通过 NAT 访问外网的 B 主机时,就会在 NAT 上打个“洞”,所有知道这个“洞”的主机都可以通过它与内网主机上的侦听程序通信。
实际上,这里所谓的“打洞”就是在 NAT 上建立一个内外网的映射表。你可以将该映射表简单地认为是一个 4 元组,即:
{
内网IP,
内网端口,
映射的外网IP,
映射的外网端口
}
在 NAT 上有了这张映射表,所有发向这个“洞”的数据都会被 NAT 中转到内网的 host 主机。而在 host 主机上侦听其内网端口的应用程序就可以收到所有的数据了
还是以上面那张图为例,如果 host 主机与 B 主机“打洞”成功,且 A 与 C 从 B 主机那里获得了 host 主机的外网 IP 及端口,那么 A 与 C 就可以向该 IP 和端口发数据,而 host 主机上侦听对应端口的应用程序就能收到它们发送的数据。
如果你在网上查找 NAT 穿越的相关资料,一定会发现大多数打洞都是使用的 UDP 协议。之所以会这样,是因为 UDP 是无连接协议,它没有连接状态的判断,也就是说只要你发送数据给它,它就能收到。而 TCP 协议就做不到这一点,它必须建立连接后,才能收发数据,因此大多数人都选用 UDP 作为打洞协议。
\
2. IP 限制锥型 NAT
IP 限制锥型要比完全锥型 NAT 严格得多,它主要的特点是,host 主机在 NAT 上“打洞”后,NAT 会对穿越洞口的 IP 地址做限制。只有登记的 IP 地址才可以通过,也就是说,只有 host 主机访问过的外网主机才能穿越 NAT。
而其他主机即使知道“洞”的位置,也不能与 host 主机通信,因为在通过 NAT 时,NAT 会检查 IP 地址,如果发现发来数据的 IP 地址没有登记,则直接将该数据包丢弃。
所以,IP 限制锥型 NAT 的映射表是一个 5 元组,即:
{
内网IP,
内网端口,
映射的外网IP,
映射的外网端口,
被访问主机的IP
}
还是以上图为例,host 主机访问 B 主机,那么只有 B 主机发送的数据才能穿越 NAT,其他主机 A 和 C 即使从 B 主机那里获得了 host 主机的外网 IP 和端口,也无法穿越 NAT。因为 NAT 会对通过的每个包做检测,当检查发现发送者的 IP 地址与映射表中的“被访问主机的 IP”不一致,则直接将该数据包丢弃。需要注意的是,IP 限制型 NAT 只限制 IP 地址,如果是同一主机的不同端口穿越 NAT 是没有任何问题的。
3. 端口限制锥型
端口限制锥型比 IP 限制锥型 NAT 更加严格,它主要的特点是,不光在 NAT 上对打洞的 IP 地址做了限制,而且还对具体的端口做了限制。因此,端口限制型 NAT 的映射表是一个 6 元组,其格式如下:
{
内网IP,
内网端口,
映射的外网IP,
映射的外网端口,
被访问主机的IP,
被访问主机的端口
}
在该 6 元组中,不光包括了 host 主机内外网的映射关系,还包括了要访问的主机的 IP 地址及提供服务的应用程序的端口地址。