
1. 从两个看不见的协议说起为什么ping通了不代表网络就通了很多人学网络协议时有个典型误区把TCP/IP四层模型背得滚瓜烂熟知道IP负责寻址、TCP负责可靠传输却对ICMP和ARP这两个打杂的协议不屑一顾。结果一到实际排障就露馅——明明IP配对了、网关填了、网线也插着就是ping不通或者ping得通外网但局域网里某台机器死活访问不了。这类问题十有八九不在IP层而是卡在ICMP或ARP上。ICMPInternet Control Message Protocol网际控制报文协议和ARPAddress Resolution Protocol地址解析协议是我个人认为整个网络体系里性价比最高的两个协议它们本身不传输业务数据却决定了数据能不能真正发出去、出错后你能不能知道原因。ICMP管的是报信——网络出错、目标不可达、超时都是它在往回传消息ARP管的是问路——知道对方的IP但不知道对方网卡的物理地址就得靠它在局域网里喊一嗓子。这篇内容我打算从这两个协议的真实工作机制讲起把报文格式、交互流程、常见故障现象和排查手法串起来中间穿插我在实际调试中踩过的坑。适合刚学完计算机网络基础、想搞清楚协议到底怎么跑起来的同学也适合已经工作、但排障时只会ping一下就说网有问题的朋友。读完之后你至少能做到两件事看到抓包里的ICMP报文能读懂类型码含义遇到ping不通能按ARP→ICMP的顺序分层定位而不是盲目重启设备。先明确一个前提这两个协议都工作在IP层之上或紧贴IP层。ICMP报文封装在IP包里协议号是1ARP报文不封装在IP包里它直接在以太网帧上跑 EtherType是0x0806。这个差异很关键后面排查故障时会反复用到。2. ICMP报文格式拆解从Type和Code两个字节读懂网络在说什么2.1 报文头部的固定结构与校验和的计算ICMP报文的前四个字节是固定格式Type类型1字节、Code代码1字节、Checksum校验和2字节。后面的内容随类型不同而变化。很多人抓包时只盯着Type看其实Code才是细分原因的关键——同样是Type 3目的不可达Code 0是网络不可达、Code 1是主机不可达、Code 3是端口不可达排查方向完全不同。校验和的计算容易出问题。ICMP的校验和只覆盖ICMP报文本身不包含前面的IP头这和TCP/UDP不同TCP/UDP的伪首部要包含IP地址。算法是把报文按16位分组全部相加有进位就回卷加到低位最后取反。我在写脚本构造ICMP包时踩过一次坑忘了把Checksum字段先置0再计算导致发出去的包全被目标主机丢弃抓包看起来发出去了但对方毫无回应。这个细节在手工构造探测包时一定要记住。下面是一个最简化的ICMP Echo请求报文结构我习惯用这个表来对照抓包字段长度典型值Echo请求说明Type1字节88请求0应答Code1字节0Echo类型固定为0Checksum2字节动态计算计算前须置0Identifier2字节进程ID用于匹配请求与应答Sequence2字节递增序号判断丢包与乱序Data可变任意填充常用来算RTTIdentifier这个字段值得多说一句。系统自带的ping程序会用进程号填充它这样多个ping进程同时跑的时候各自收到的应答不会串台。你自己写探测工具时如果随便填个固定值在多任务环境下就会收到别人的应答导致延迟计算完全错乱。Sequence则是用来算丢包率的发10个收8个序号断在哪儿一目了然。2.2 常见Type/Code组合与它们的真实含义ICMP的类型有几十种但实际排障中高频出现的就那么几种。我把它们整理成一张对照表建议直接记住TypeCode含义典型触发场景00Echo应答对方正常响应ping30/1/3网络/主机/端口不可达路由缺失、目标关机、端口未监听50/1重定向网关发现更优路径80Echo请求本机发起ping110/1超时TTL耗尽、分片重组超时120参数问题IP头字段有误Type 3 Code 3端口不可达特别有意思。我用它做过一个小实验向一台开着防火墙的主机发UDP包到某个没监听的端口对方会回一个ICMP端口不可达但如果防火墙直接DROP就什么都不会回。这两种现象的差异正好可以用来判断目标主机是活着但拒绝还是根本没在。Type 11超时是traceroute的工作原理。它故意把TTL设成1、2、3递增每经过一个路由器TTL减1减到0时路由器丢弃包并回一个ICMP超时消息消息里带着路由器的IP。这样一路收集下去路径就画出来了。理解这一点之后你就明白为什么某些路由器上traceroute会出现星号——不是网络断了是那台设备配置了不回应ICMP超时或者被安全策略拦了。2.3 ICMP不是ping专用差错报文与查询报文的区别不少人以为ICMP就是ping和traceroute用的这理解太窄。ICMP分两大类查询报文Echo请求/应答、时间戳请求/应答和差错报文目的不可达、超时、重定向、参数问题。差错报文是网络设备主动报告问题的手段没有它你只能看到连接超时这种模糊提示根本不知道卡在哪一跳。有个容易被忽略的规则ICMP差错报文本身不会再触发另一个ICMP差错报文。这是为了防止广播风暴——如果一个包出错回的差错包又出错再回差错包就无限循环了。所以你在抓包里看到差错报文的时候它里面封装的原始IP头和前8字节数据就是出问题的那个包的身份信息。我排查过一次MTU问题就是靠ICMP Type 3 Code 4需要分片但设置了DF位报文里带回来的原始包大小一眼看出是路径上某个环节MTU变小了。安全策略上很多环境会限制ICMP。这里要提醒完全禁ping不等于安全反而会让排障失去最基础的手段。我的做法是内网放行Echo边界设备限制差错报文的速率既能排障又不至于被打爆。3. ARP的工作现场一次局域网通信里它到底在什么时候出场3.1 从我知道你IP到我知道你网卡的完整链路ARP解决的是一个非常具体的问题以太网帧的头部需要目的MAC地址而应用程序只知道目的IP。协议栈在发数据前会查ARP缓存表命中就直接封装没命中就发一个ARP请求广播出去内容是谁的IP是192.168.1.100请告诉我你的MAC源MAC填自己的。局域网内所有主机都能收到这个广播但只有IP匹配的那台会回一个ARP应答单播回给请求方。这里有几个细节值得抠ARP请求是广播应答是单播。请求帧的目的MAC是全FFF:FF:FF:FF:FF:FF交换机收到后会泛洪到所有端口应答则直接发给请求方。抓包时如果看到ARP应答也是广播那基本可以判定有设备在搞异常行为。缓存有老化时间。Linux默认的ARP缓存条目大概在几十秒到几分钟不等受内核参数影响Windows也类似。缓存过期后会重新发起请求。所以你在两台机器之间持续ping抓包会看到隔一段时间冒出一个ARP请求这是正常的。免费ARPGratuitous ARP。主机启动或IP变更时会主动广播一个我是谁谁谁的ARP目的是让别人更新缓存、同时检测IP冲突。如果收到回应说明局域网里有另一台机器用了同样的IP。这个机制在排查IP冲突时非常好用。我用一个表格把ARP交互的时序整理清楚步骤方向帧类型关键字段1请求方→广播ARP请求目标MAC全F目标IP待解析2目标→请求方ARP应答单播携带自身MAC3请求方写入缓存条目带老化计时4数据发送以太网单播用解析到的MAC封装3.2 ARP缓存的查看、清理与老化参数动手能力这块命令行必须熟。Linux下用ip neigh老一点的系统用arp -nWindows下用arp -a。看缓存的时候注意状态字段REACHABLE表示有效STALE表示过期但还能用下次通信会重新确认DELAY/PROBE是正在探测。很多莫名其妙不通的问题就是缓存里留了一条STALE甚至错误的条目。# Linux 查看ARP缓存 ip neigh show # 清理指定条目 sudo ip neigh del 192.168.1.100 dev eth0 # 查看ARP相关内核参数 sysctl net.ipv4.neigh.default.gc_stale_time清理缓存这个操作我建议养成习惯更换网络设备、调整IP规划、或者怀疑IP冲突之后第一时间清一遍。因为缓存里的旧MAC会让流量继续往错误的方向发表面上看IP是对的实际帧发给了别的机器非常迷惑。老化参数方面gc_stale_time控制条目多久算过期默认60秒左右gc_interval是垃圾回收周期。这些一般不用动但在一些设备频繁上下线的环境比如测试实验室把老化时间调短能减少设备换了MAC但缓存没更新的问题。提示清理ARP缓存只能在有权限的机器上做且只影响本机。如果怀疑全网有错误条目需要逐台排查或者检查是否存在ARP欺骗。3.3 代理ARP、免费ARP与几类容易混淆的场景代理ARPProxy ARP是个容易绕晕的机制路由器收到ARP请求如果目标IP在它的另一个网段且它愿意转发它会用自己的MAC回应让请求方把流量先发给它。这在小规模网络里能省掉配路由的麻烦但排障时会让人抓狂——你以为在跟目标主机通信其实一直在跟路由器说话。免费ARP前面提过用途有两个宣告和检测冲突。有个实际场景很典型一台服务器更换了网卡MAC变了但IP没变如果不发免费ARP其他机器的缓存里还是旧MAC通信就断了。很多服务器操作系统在网卡up时会自动发但也有不发的情况这时候手动触发一下或者直接清缓存最省事。还有一个易混点ARP只在本广播域内工作。跨网段的通信ARP解析的其实是网关的MAC不是最终目标的MAC。所以你在A网段ping B网段的主机抓包看到的ARP请求目标是网关IP这是对的别误以为出了问题。4. 实操验证用抓包和命令行把两个协议看出来4.1 搭建最小实验环境与抓包位置选择光看理论没用我建议动手抓一次包。最小环境两台机器接同一台交换机或者一台虚拟机加宿主机的桥接网络配同网段IP。抓包工具用tcpdump或Wireshark都行命令行的tcpdump更适合快速过滤。抓包位置很关键。如果你在请求方抓能看到ARP请求和应答如果在目标方抓只能看到请求广播会到达和它自己发的应答。想看完整交互最好在中间交换机做端口镜像或者干脆在请求方抓——因为请求方既发请求又收应答信息最全。# 只抓ARP sudo tcpdump -i eth0 -nn arp # 只抓ICMP sudo tcpdump -i eth0 -nn icmp # 同时抓带详细输出 sudo tcpdump -i eth0 -nn -e arp or icmp-nn的作用是不做名字解析避免DNS反查拖慢输出-e会打印以太网头部能直接看到源目MAC判断ARP阶段特别有用。我第一次抓的时候没加-e看到一堆IP层信息完全没意识到ARP帧里根本没有IP头。4.2 一次完整的ping过程在抓包里长什么样清空ARP缓存后ping一个同网段地址抓包会呈现这样的顺序ARP请求广播问目标IP的MACARP应答单播目标报上自己的MACICMP Echo请求单播用刚学到的MAC封装ICMP Echo应答单播反向回来如果第二次pingARP那两步就没了直接从ICMP开始因为缓存命中。这个对比非常直观能让你彻底理解缓存的作用。跨网段的情况完全不同ARP解析的是网关然后ICMP包发给网关由网关继续转发。抓包里你只能看到本网段这段后面几跳看不到。想知道后面发生了什么得用traceroute或者在各跳上分别抓。4.3 用TTL和RTT反推网络状况的实用技巧ping的输出里有TTL和time两个值很多人只看通不通浪费了信息。TTL是经过多少跳之后剩下的值初始值常见64Linux、128Windows、255网络设备。用初始值减去收到的TTL就是大致跳数。比如收到TTL57大概率是Linux目标经过了7跳。这个估算在判断请求是不是绕了远路时很有用。RTT往返时间的波动更能说明问题。稳定在几毫秒说明链路健康忽高忽低说明有拥塞或无线干扰突然从1ms跳到200ms常见原因是走了不同的路径或者中间设备在限速。我习惯用ping -c 100跑一批看统计里的mdev平均偏差比单看某一次的time靠谱得多。# 跑100个包看延迟分布 ping -c 100 192.168.1.1 # 指定包大小测试MTU相关行为 ping -c 4 -s 1472 192.168.1.1 # 不允许分片Linux ping -c 4 -M do -s 1472 192.168.1.1-s 1472这个数字不是随便来的以太网MTU是1500减去IP头20字节和ICMP头8字节正好1472。如果这个大小能通而更大的不通说明路径MTU就是1500中间没有额外封装如果不通可能存在PPPoE之类的额外开销。5. 故障排查实录三类典型ping不通的分层定位过程5.1 同网段不通先看ARP有没有解析成功前几天帮人看一个问题两台机器同接一台交换机IP都在192.168.1.0/24互相ping不通。对方已经检查过IP、掩码、防火墙一筹莫展。我让他先看ARP缓存——果然ip neigh里目标IP的状态是INCOMPLETE意思是请求发出去了但没人应答。这就把问题范围缩到了二层。继续查目标机器的网卡是不是up交换机端口是不是同一个VLAN有没有做端口隔离最后发现是交换机上开了端口隔离两个端口不能互通。整个过程五分钟靠的就是先看ARP状态这一步。排查顺序我总结成ARP缓存状态 → 抓包看请求有没有发出 → 看有没有应答 → 看交换机配置。ARP请求发不出去查本机网卡和路由发了没应答查二层连通性和目标主机状态。这个链路比盲目试错快得多。5.2 跨网段不通ARP通了但ICMP差错报文指向哪里跨网段的问题ARP一般能解析到网关除非网关本身不可达所以故障点往往在后面。这时候要看有没有ICMP差错报文回来。如果收到Type 3 Code 0网络不可达说明某台路由器没有到目标网段的路由Code 1主机不可达通常是最后一跳路由器找不到目标主机可能是目标关机或者ARP在那边失败了。还有一种情况是什么差错报文都没有就是超时。这可能是中间设备静默丢包也可能是目标防火墙直接DROP。区分方法用traceroute看能走到哪一跳如果走到某一跳之后全是星号问题就在那附近。注意前面说过星号也可能是设备不回应ICMP所以要结合其他手段比如换TCP端口探测。我遇到过一次特别隐蔽的能ping通网关ping不通同网段的另一台机器但那台机器ping别人都正常。最后发现是对方主机上的防火墙规则只允许特定源IPICMP请求被静默丢弃连差错报文都不回。这种只能靠在对端抓包确认——请求到了但没回应答。5.3 IP冲突与ARP欺骗的识别特征IP冲突的表现很有规律网络时通时断ARP缓存里的MAC会来回变。用arping工具可以主动检测# 检测IP冲突收到多个不同MAC的应答就是冲突 sudo arping -I eth0 192.168.1.100正常情况下应该只有一个MAC回应。如果收到两个不同的MAC基本可以确定冲突。免费ARP也能起类似作用。ARP欺骗的特征是网关的MAC突然变了或者缓存里出现静态条目被篡改。排查方法是对比预期的网关MAC和缓存里的实际值不一致就要警惕。防御手段包括在交换机上配置端口安全、绑定IP-MAC、使用动态ARP检测等。这些属于网络管理范畴但作为排障人员必须知道现象长什么样否则会把攻击误判成网络不稳定。6. 几个容易踩的坑和我的处理习惯6.1 防火墙放行ICMP的粒度问题很多人配置防火墙时一刀切要么全放要么全禁。实际上ICMP应该按类型放行。Echo请求/应答可以放便于排障但差错报文建议放行且做速率限制因为路径MTU发现依赖Type 3 Code 4全禁了会导致大包传输莫名其妙卡住——现象是能ping通小包传文件时卡死非常难查。我自己的习惯是入方向放行Echo和相关应答差错报文限制每秒数量重定向报文一般禁掉防止被利用做路由劫持。这套策略在大多数环境够用。6.2 ARP缓存的静态绑定什么时候值得做静态ARP绑定能防欺骗但维护成本高。我的经验是只在关键设备上做网关、核心服务器。普通终端做静态绑定设备一换就得手工改得不偿失。绑定命令也简单# 添加静态ARP条目Linux sudo ip neigh add 192.168.1.1 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanent注意nud permanent表示永不老化。加了之后要记得记录否则过几个月自己都忘了为什么这台机器换IP后不通。6.3 虚拟化环境里ARP的特殊表现虚拟机环境里ARP经常出怪问题。比如容器或虚拟机迁移后MAC变了但上游交换机的转发表没更新流量还往旧端口发导致短时间不通。这时候清ARP缓存往往没用得等交换机MAC表老化或者在迁移后主动发免费ARP。还有网桥和NAT场景ARP请求可能被宿主机的代理ARP截胡表现为虚拟机以为目标在同一网段实际流量全走了宿主机。抓包时看到应答的MAC是网关而不是目标主机就该意识到有代理ARP在起作用。6.4 抓包时最容易忽略的过滤技巧最后分享几个过滤表达式能省很多时间需求tcpdump 过滤只看某主机相关ICMPicmp and host 192.168.1.100只看Echo请求icmp[icmptype] 8只看目的不可达icmp[icmptype] 3只看ARP请求arp[6:2] 1排除自己产生的包not src host 本机IPicmp[icmptype]这种偏移量写法刚开始不习惯用几次就顺了。ARP的arp[6:2] 1表示操作码为1请求等于2是应答。这些表达式在Wireshark里也能用只是语法略有差异。我个人在实际操作中的体会是ICMP和ARP这类底层杂活协议的价值往往在出问题时才体现出来。平时多抓几次包、多看一眼缓存状态把这些动作变成肌肉记忆真遇到故障时就能少走很多弯路。网络排障最忌讳的就是一上来就猜分层看、逐步缩小范围永远比反复重启有效。