【从0开始学习计算机网络】| ARP 协议:地址解析,ARP 欺骗,链路层寻址

🌈个人主页 :一条泥憨鱼(欢迎各位大佬莅临)

❄️《数据结构》 ❄️《AI与Agent那些事》

❄️《从0开始学计算机网络》 ❄️《后端开发》

抓包时偶尔会看到没人问就自己冒出来的 ARP 应答,还反复刷新某个网关的 MAC。这篇从 ARP 的定位讲起,走完请求应答、跨网段解析、欺骗原理和防御手段,最后给出一个判断这类协议风险的通用角度。

为什么需要 ARP:IP 地址和 MAC 地址是两套体系

IP 地址是逻辑地址,用来在网络层标识一台主机"在网络拓扑里的位置",它可路由、可跨网段、可以随主机移动而改变。MAC 地址是链路地址,烧在网卡上,用来在同一段以太网里标识"具体是哪块网卡",它不可路由,只在本地链路有意义。

这两套体系各管一段。IP 层负责端到端的寻址和路由决策,决定这个包该从哪个接口出去、下一跳是谁;以太网层负责把帧从一个网卡送到同一链路里的另一个网卡,它只认 MAC 地址,帧头里的目的 MAC 决定了哪块网卡会接收。

问题就出在这两层的衔接处:上层已经算出了下一跳的 IP,可下层要的是 MAC。没有 ARP,主机只能靠手工维护一张"IP 到 MAC"的映射表,网络里任何一台机器换网卡、改 IP、加机器,都得全网同步一遍,这在动态网络里根本不可行。

ARP 就是填这个缝的:它在同一网段内把 IP 地址翻译成 MAC 地址,让 IP 层算出的下一跳能落到具体的网卡上。注意它的作用范围------ARP 只在本地链路内工作,不跨路由器转发,这是后文理解跨网段解析的关键。

ARP 工作流程:一次请求,一次应答

先看报文。一个 ARP 报文固定 28 字节(不含以太网帧头),关键字段有:

  • 发送方 MAC、发送方 IP:告诉对方"我是谁"

  • 目标 MAC、目标 IP:请求时目标 MAC 填全 0,因为还不知道

  • 操作码:1 表示请求,2 表示应答

整个交互只有两步:

  1. 主机 A 要发包给同网段的 IP 192.168.1.20,查本地 ARP 缓存没有对应项,于是构造 ARP 请求,目的 MAC 填广播地址 ff:ff:ff:ff:ff:ff,发出去。

  2. 同网段所有主机都收到这个广播,但只有 IP 等于 192.168.1.20 的主机 B 会处理:它把 A 的 IP 和 MAC 记进自己的缓存,然后构造 ARP 应答,目的 MAC 填 A 的 MAC,单播发回。

为什么请求用广播、应答用单播?请求时 A 只知道 IP、不知道 MAC,广播是唯一能触达"未知目标"的方式。应答时 B 已经知道了 A 的 MAC(请求报文的发送方 MAC 字段里带着),没必要再广播打扰全网,单播更省带宽。这个设计本身没问题,问题在于应答的接收方不做任何验证。

收到应答后,A 把映射写进 ARP 缓存,后续发包直接查表。缓存不是永久的,Linux 默认条目在可达状态下约几十秒到几分钟,具体值由内核参数决定,可以用 ip neigh 或 arp -a 查看:

bash 复制代码
# 查看本机 ARP 缓存

arp -a



# 或者用 iproute2 的工具,能看到条目状态

ip neigh show

抓包验证一下这个过程:

bash 复制代码
# 在 Linux 上抓 ARP 流量,-n 不做域名解析,-e 显示链路层地址

sudo tcpdump -n -e arp

正常看到的是:一个 Request who-has 192.168.1.20 tell 192.168.1.10 的广播,紧接着一个 Reply 192.168.1.20 is-at ... 的单播。缓存老化后,同样的请求会重新出现------这就是定期刷新。

跨网段时 ARP 解析的是谁

这是最容易搞混的一点:如果目标 IP 不在本网段,ARP 解析的是网关的 MAC,不是最终目标的 MAC。

主机发包前先拿目标 IP 和自己的子网掩码做与运算,判断是否同网段:

  • 同网段:ARP 解析目标 IP 本身。

  • 不同网段:目标不在本地链路可达范围内,必须交给网关转发。此时主机 ARP 解析的是网关 IP,拿到网关 MAC 后,把帧的目的 MAC 填成网关,IP 包里的目的 IP 仍然是最终目标。

用路由表看这个逻辑更清楚:

bash 复制代码
# 查看路由表

ip route show



# 典型输出

# default via 192.168.1.1 dev eth0

# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10

去 192.168.1.0/24 的包走 eth0 直连,ARP 解析目标本身;去其他地址的包匹配 default 走网关 192.168.1.1,ARP 解析的是 192.168.1.1。所以跨网段抓包时,帧头的目的 MAC 是网关的,不是对端的------看到这个别以为是配置错了。

这也解释了一件事:ARP 欺骗如果想劫持跨网段流量,攻击者伪造的是网关的映射,而不是远端目标的映射,因为主机缓存里压根不存在远端目标的 MAC。

ARP 欺骗的原理:无状态、无认证的信任模型

回到开头那个"莫名多出来的应答"。ARP 协议在设计时假设同一链路里的主机都是可信的,因此它的信任模型非常宽松:

  • 主机收到 ARP 应答,不管自己有没有发过请求,都会更新缓存(这是协议允许的"免费 ARP"行为)。

  • 应答里没有任何认证字段,无法验证发送方是否真的是它声称的那个 IP。

  • 缓存更新是无条件的,后来的应答直接覆盖先前的条目。

这三条合起来就是一个可以被利用的缺口。攻击者只要持续向 A 发送伪造应答"网关 IP 的 MAC 是我",A 的缓存里网关映射就被改成攻击者的 MAC。同理,攻击者再向网关发送"主机 A 的 IP 的 MAC 是我",网关的缓存也被污染。

双向污染之后,A 发给网关的流量先到攻击者,攻击者再转发给真正的网关;网关回给 A 的流量也先到攻击者。攻击者成了中间人,可以监听、篡改甚至丢弃流量。关键在于:如果攻击者只做转发不做修改,两端通信完全正常,用户侧没有任何异常感知------这也是这类攻击难发现的原因。

复现要在隔离环境里做,比如两台虚拟机加一个攻击机,不能在生产网络里试。思路是:用 arpspoof 或 ettercap 指定目标和网关,向目标持续发送伪造应答,然后在目标机上用 arp -a 观察网关条目是不是变成了攻击机的 MAC。危害边界也要说清楚:ARP 欺骗只能影响同一广播域内的主机,跨路由器后 ARP 不再转发,攻击范围受限于本地网段;而且它劫持的是链路层映射,对启用了端到端加密的流量(如 HTTPS、SSH),攻击者拿到的仍是密文,能做的更多是流量分析、降级和阻断,而非直接读取内容。

防御与检测:从静态绑定到动态监测

按防护强度从弱到强,常见的手段有这几种。

静态 ARP 绑定:在主机上手写网关的 IP-MAC 映射,设为永久条目,不受应答覆盖。简单有效,但维护成本高------网络里任何一台机器换网卡都要手工更新,规模一大就不可行。适合少量关键服务器固定网关的场景。

DHCP Snooping:在交换机上开启后,交换机监听 DHCP 交互,建立"端口-MAC-IP"的绑定表,并丢弃非信任端口上伪造的 DHCP 应答。它本身不是防 ARP 的,但它是下一项的前提。

动态 ARP 检测(DAI):交换机依据 DHCP Snooping 建立的绑定表,校验经过的 ARP 报文,源 IP 和源 MAC 与绑定表不符就丢弃。这是目前园区网里比较有效的方案,但有个硬依赖:主机必须通过 DHCP 获取地址,静态配置 IP 的主机没有绑定记录,DAI 会误杀它们的正常 ARP。所以纯静态 IP 环境用不了 DAI。

端口安全:限制每个交换机端口上允许出现的 MAC 数量,防止攻击者伪造大量 MAC 泛洪。它针对的是 MAC 泛洪类攻击,对单点 ARP 欺骗作用有限。

监测工具:arpwatch 这类工具监听 ARP 流量,发现某个 IP 的 MAC 映射发生变化时告警。它只做检测不做阻断,适合作为辅助告警手段。

对后端和运维来说,可落地的判断顺序是:园区网优先上 DHCP Snooping + DAI;服务器区可以用静态绑定兜底;无论用哪种,都要配 ARP 监测做兜底告警,因为静态绑定会漏、DAI 依赖 DHCP,没有哪种方案能单独覆盖全部场景。

最后

ARP 的这些问题不是实现 bug,而是设计时假设了可信网络:它诞生在一个主机互相信任、链路封闭的环境里,认证和防伪从来不在设计目标中。等网络变得开放,这个假设就成了缺口。判断一个协议是否面临同类风险,可以套一个简单的问法:它是否在无认证的前提下自动信任对端声明?如果是,再问一句------这条声明被伪造,后果是什么。ARP 的答案是流量被劫持,DNS 的答案是解析被投毒,BGP 的答案是路由被劫持。凡是符合这个模式的协议,都值得单独看一眼它的信任边界。

相关推荐
2501_933923251 小时前
SpringCloud组件:Eureka服务注册与发现
java·开发语言·后端·spring cloud·eureka
m0_715674431 小时前
数据分类分级的范式转换:从规则匹配到场景化高准确率一键部署
大数据·网络·人工智能·网络安全
leikooo1 小时前
ARTS 1011: 双堆动态对顶求中位数、IPC 注入与空密码串联接管账户与程序从不做决策
后端
合尘猫1 小时前
AI 项目上线就停:一次事件循环阻塞的完整排查过程
人工智能·后端·python
Re_zero1 小时前
一次 SSE 断流排查:PrintWriter 吞掉了我的 IOException
java·后端
HY小宝F1 小时前
树莓派智能摄像头系统 30 天重学计划之 Day 04 · HTTP / API:控制链入口 —— 学习总结
网络协议·学习·http
1m555555551 小时前
RAG 工程实战(四):明明召回了正确知识,为什么最终 Top-K 还是漏了?
后端
我是人✓2 小时前
Java核心语法:作用域、循环与大数值处理
java·开发语言·后端
newerp2 小时前
GC Pacer 调优算法:GOGC、GOMEMLIMIT 与容器 OOM 防御
后端·程序员·go