大家好,我是HLAIA光子。
本文来讲讲三个网络协议:DNS、NAT 和 ARP。它们做的事情看起来不一样,但本质上都在干同一件事:地址翻译。
DNS 把域名翻成 IP 地址,NAT 把私有 IP 翻成公网 IP,ARP 把 IP 地址翻成 MAC 地址。
你在浏览器里敲下一个网址到页面打开,就会用到这三个协议,缺一不可。
我按一条完整的请求链路来讲,从你输入域名开始,一步步看这三个协议是怎么配合工作的。
DNS
域名为什么需要"翻译"
IP 地址是互联网通信的基础,但让人记住 93.184.216.34 这种东西显然不现实。域名就好记多了,www.baidu.com 一看就知道是什么网站。问题是,网络设备只认 IP 地址,不认域名。所以需要一个机制把域名翻译成 IP 地址,这就是 DNS 干的事。
DNS 本质上是一个分布式的数据库系统,没有哪个服务器是存了所有的域名记录的,记录分散在全世界的 DNS 服务器上,每秒都有新的域名诞生,每秒也有旧的域名废弃。大家通过查询协议协作完成翻译。
域名的层级结构
域名是分层的,从右到左级别递增。以 www.example.com. 为例,最右边的 . 是根域,通常省略不写。.com 是顶级域,example 是二级域,一般由组织注册。www 是三级域,由组织自己管理。
这个层级结构直接决定了 DNS 的查询方式。没有一台服务器知道所有域名的 IP,但每一层的服务器都知道"下一层该去哪问"。
解析过程:递归加迭代
DNS 解析涉及两种查询方式:递归查询和迭代查询。
递归查询的意思是"你帮我查到底",被查询的服务器要负责拿到最终结果再返回。迭代查询的意思是"我不知道,但你可以去问谁",被查询的服务器只告诉你下一步该找谁。
实际一次完整的 DNS 解析,两种查询都会用到:
- 你的电脑向本地 DNS 服务器发起请求,这是递归查询
- 本地 DNS 服务器代替你去跑腿,依次问根 DNS、顶级域 DNS、权威 DNS,这个过程是迭代查询
- 权威 DNS 返回最终的 IP 地址,本地 DNS 把结果缓存起来,返回给你
主机到本地 DNS 是递归,本地 DNS 往后是迭代。
记录类型
DNS 服务器里存的不是一张简单的域名-IP 对照表,而是多种类型的资源记录。最常用的几种:
A 记录是最基本的,把域名直接指向一个 IPv4 地址。
www.example.com. IN A 93.184.216.34
CNAME 记录是别名,一个域名指向另一个域名。常用于 blog.example.com 和 www.example.com 指向同一个服务器。注意 CNAME 不能和 A 记录、MX 记录共存于同一个域名。
MX 记录专门用来指定邮件服务器,带优先级数字,数字越小优先级越高。
example.com. IN MX 10 mail1.example.com.
example.com. IN MX 20 mail2.example.com.
还有 AAAA 记录对应 IPv6 地址,NS 记录指定域名由哪台 DNS 服务器解析,TXT 记录存文本信息,常用于域名验证。
缓存机制
DNS 查询不会每次都从头跑到尾。浏览器有缓存,操作系统有缓存,路由器有缓存,ISP 的 DNS 服务器也有缓存。每一层都会把查过的结果存一段时间,这个时间由 TTL 控制。TTL 越短,DNS 变更生效越快,但查询压力越大。TTL 越长,查询压力小,但改了 DNS 配置后需要等更久才能生效。
DNS 的安全问题
DNS 协议设计的时候没怎么考虑安全,这也带来了不少问题。DNS 劫持是攻击者拦截你的 DNS 查询,返回一个假的 IP 地址,把你引导到恶意网站。DNS 污染是往 DNS 缓存里注入虚假记录,影响范围更大。
针对这些问题,业界搞了几种安全增强技术。DNSSEC 通过数字签名保证 DNS 数据没被篡改,但不加密查询内容。DoH 用 HTTPS 加密 DNS 查询,DoT 用 TLS 加密,两者都能防止窃听和篡改。
日常使用中,把 DNS 服务器换成 Cloudflare 的 1.1.1.1 或者 Google 的 8.8.8.8 就能获得基本的安全保障。国内的话阿里 DNS 223.5.5.5 和腾讯 DNS 119.29.29.29 速度更快。
NAT
为什么需要地址转换
IPv4 地址总共就约 43 亿个,全球设备早就超过这个数了。如果每台设备都要一个唯一的公网 IP,地址池早就被狠狠地榨干了。
NAT 的思路很巧妙:给内部网络用私有 IP 地址,这些地址可以在不同的内网里重复使用,只有出门上网的时候才由路由器帮你转换成公网 IP。RFC 1918 定义了三段私有地址范围:
- A 类:
10.0.0.0 ~ 10.255.255.255,约 1677 万个 - B 类:
172.16.0.0 ~ 172.31.255.255,约 104 万个 - C 类:
192.168.0.0 ~ 192.168.255.255,约 6.5 万个
你家里路由器的 LAN 口大概率就是 192.168.x.x,这就是 C 类私有地址。
三种 NAT
静态 NAT 是一对一的固定映射,一个私有 IP 对应一个公网 IP。一般用在内部服务器需要对外提供服务的场景,比如公司的 Web 服务器。
动态 NAT 也是一对一,但公网 IP 是从一个地址池里动态分配的,先到先得。用完了就得等别人释放。
NAPT 是最常用的方式,也叫 PAT。多个内网主机共享一个出口 IP,通过端口号来区分不同的会话。你家用的路由器基本就是这种方式,十几台设备上网靠的就是端口号来区分谁是谁。
NAPT 的转换过程是这样的:
- 内网主机
10.1.1.100:5000发请求到外网服务器93.184.216.34:80 - 数据包到达路由器,路由器把源 IP 替换成 WAN 口 IP,源端口替换成路由器分配的新端口,比如
202.1.1.1:20001,同时在转换表里记下对应关系 - 服务器响应时,数据包回到路由器,目的端口是
20001 - 路由器查转换表,把目的 IP 和端口反向替换回
10.1.1.100:5000,数据包送达内网主机
整个过程对内网主机和外网服务器都是透明的,双方都不知道 NAT 的存在。
家里的路由器真的映射到了公网 IP 吗
上面说路由器把私有 IP 转换成 WAN 口 IP,但这个 WAN 口 IP 不一定是公网 IP ,而且国内的家里的 IP 基本都不是。
大概十多年前吧,那时候在国内的一些地方 开通家庭宽带,都送公网IP的。现在只有去运营商申请,价格死贵,而且大概率不是固定的 IP。
虽然现在每家的 IPV6 大概率是公网的,但是 IPV6 还没有普及,很多网站不支持。
运营商手里公网 IP 也不够用,所以它的做法是给你家路由器分配一个运营商内部的私有 IP,比如 10.45.67.89 或者 100.64.x.x。然后在运营商自己的设备上再搞一层 NAT,把你这个私有 IP 转成真正的公网 IP。这个技术叫 CGNAT,运营商级 NAT。
所以你家里的数据包要出去,实际上经过了两层 NAT:
NAT 穿透
NAT 解决了地址不够用的问题,但也带来了一个副作用:外部无法主动连接内部主机。这在大多数场景下是好事,等于自带了一层安全防护。但对 P2P 通信来说就很头疼了,视频通话、文件传输这类场景都需要双方直接通信。
解决方案有几种。STUN 让客户端通过一个公网服务器发现自己的公网映射地址,然后尝试直接打洞连接。TURN 的穿透方式,就是通过一个中继服务器转发所有数据,Frp 反代就类似这种方式。ICE 是一个整合框架,依次尝试直连、STUN 打洞、TURN 中继,选最优路径。WebRTC 就是用 ICE 来建立 P2P 连接的。
喜欢折腾NAS的玩家应该很熟悉吧
ARP
为什么需要 IP 到 MAC 的翻译
在局域网里,数据帧的传输靠的是 MAC 地址,不是 IP 地址。交换机根据 MAC 地址转发帧,网卡只接收目标 MAC 是自己的帧。但上层应用只知道 IP 地址,不知道目标设备的 MAC 地址。所以需要一个机制把 IP 翻成 MAC,这就是 ARP 干的事。
ARP 的工作流程
同一个子网内的 ARP 解析过程如下:
- 主机 A 先查自己的 ARP 缓存表,看有没有目标 IP 对应的 MAC 地址
- 缓存没命中,就在局域网里广播一个 ARP 请求包,问 IP 是
192.168.1.2的主机 MAC 地址是多少 - 局域网里所有主机都会收到这个广播,但只有 IP 匹配的主机 B 会单播回复自己的 MAC 地址
- 主机 A 把这个映射存入 ARP 缓存表,后续直接用 MAC 地址通信
ARP 请求是广播,一对多,ARP 应答则是单播。
跨子网的情况稍有不同。如果目标 IP 不在同一个子网,ARP 解析的是默认网关的 MAC 地址,不是目标主机的 MAC 地址。因为数据帧要先发给路由器,再由路由器转发到目标网络。
ARP 缓存表可以通过命令查看和管理。Windows 用 arp -a 查看,Linux 用 ip neigh show 。缓存条目有生命周期,动态条目通常几十秒到二十分钟不等会过期,过期后需要重新广播查询。
免费 ARP
先回顾一下 ARP 报文里的关键字段。每个 ARP 包都带着四个地址信息:发送方的 IP 和 MAC、目标的 IP 和 MAC。正常的 ARP 请求里,发送方填自己的 IP,目标填想查询的那个 IP。
免费 ARP 是一种特殊的 ARP 请求,特殊在它把自己的 IP 同时填在发送方 IP 和目标 IP 里。等于在向全网广播:"192.168.1.10 的 MAC 地址是谁?" 而发送方自己就是 192.168.1.10。这不是真的在问,而是借 ARP 广播的形式通知所有人:"这个 IP 对应的 MAC 是我,大家更新一下缓存表。"
它有两个实际用途。
一是检测 IP 地址冲突。主机刚配了一个新 IP,广播一个免费 ARP。如果局域网里已经有别的设备用了这个 IP,那个设备会回复一个 ARP 应答说"这个 IP 是我的",这就说明发生冲突了。没人回复才说明这个 IP 可以安全使用。
二是通知网络更新 MAC 映射。比如虚拟机从一台物理机热迁移到另一台物理机,MAC 地址变了但 IP 没变。迁移完成后发一个免费 ARP,网络中其他设备收到后会更新 ARP 缓存,把流量切到新的 MAC 上,实现无缝切换。
ARP 欺骗
ARP 协议有一个设计缺陷:不验证 ARP 应答的真实性。任何主机都可以发送一个伪造的 ARP 应答,声称某个 IP 对应的 MAC 是自己的。这就是 ARP 欺骗攻击的原理。
攻击者可以向目标主机发送伪造的 ARP 应答,把网关 IP 对应的 MAC 替换成自己的 MAC。这样目标主机的所有流量都会先经过攻击者,形成中间人攻击。攻击者可以窃听、篡改通信数据,甚至直接把流量丢到不存在的 MAC 上导致断网。
防御手段有好几层。最简单的是静态 ARP 绑定,手动配置 IP 和 MAC 的映射关系,但只适合小网络。企业网络一般用 DAI 动态 ARP 检测,配合 DHCP Snooping 形成纵深防御。
三次"翻译"怎么串起来的
到这里三个协议都讲完了,你从浏览器访问一个网站,完整的链路是这样的:
- DNS 翻译域名:浏览器把
www.example.com交给 DNS,拿到 IP 地址93.184.216.34 - ARP 翻译网关 MAC:你的电脑发现目标 IP 不在同一个子网,用 ARP 查到默认网关的 MAC 地址,把数据帧发给路由器
- NAT 翻译私有 IP:路由器收到数据包,用 NAPT 把你的私有 IP 和端口替换成公网 IP 和新端口,发到互联网上
反过来,响应数据回来的时候,NAT 反向替换,ARP 缓存已经命中不用再查,DNS 也早就把结果缓存了,整个过程对你也是完全透明的。
写在最后
DNS、NAT、ARP 这三个协议,解决的问题不同,工作的网络层次不同,但它们做的事情本质上都是地址翻译。
实际环境里,DNS 问题是最常遇到的。配置个域名解析、排查个网站打不开,都跟 DNS 有关。NAT 和 ARP 平时不太需要操心,但一旦碰到 P2P 通信或者局域网通信异常,理解它们的原理就很重要了。
如果你觉得这篇文章有帮助,点赞关注,点点赞~