你的电脑加入一个组播组时,是怎么告诉路由器和交换机“请把这个组的流量给我”的?IGMP 的报文长什么样?本机又是怎么回应查询的?这篇在 en0 上真实地加入和离开一个组,逐字节解码 IGMP 报文,并被动听 180 秒看局域网里别的设备的 IGMP 行为。
net.inet.igmp.gsrdelay: 10 net.inet.igmp.default_version: 3 net.inet.igmp.legacysupp: 0 net.inet.igmp.v2enable: 1 net.inet.igmp.v1enable: 1 net.inet.igmp.sendlocal: 1 net.inet.igmp.sendra: 1 netstat -s -p igmp 累计:收到 IGMP 报文 84112 个,其中 V1/V2 成员查询 3497 个,成员报告 80613 个(大多是别的设备发的),本机发出的成员报告 1713 个 default_version = 3:本机默认说 IGMPv3;但收到 V1/V2 查询时会按对方的版本降级回应(见第三节抓到的报告类型)
IGMPv2 只有 8 字节,IP 头带 4 字节的 Router Alert 选项,TTL 1。报告发给组地址本身,离开发给 224.0.0.2。
加入后本机发出 IGMP 报文 1 个(只算与本节操作相关的、源地址是本机的)
+ 0 ms IGMPv2 报告(0x16),IP 目的 239.255.42.99,以太网目的 01:00:5e:7f:2a:63,TTL 1,IP 头 24 字节,IGMP 部分 8 字节,组地址 = 239.255.42.99,校验和正确
离开后本机发出 IGMP 报文 1 个(只算与本节操作相关的、源地址是本机的)
+ 0 ms IGMPv2 离开(0x17),IP 目的 224.0.0.2,以太网目的 01:00:5e:00:00:02,TTL 1,IP 头 24 字节,IGMP 部分 8 字节,组地址 = 239.255.42.99,校验和正确
IGMPv2 报文固定 8 字节:类型 1 + 最大响应时间 1(单位 0.1 秒)+ 校验和 2 + 组地址 4;校验和是对这 8 字节做的互联网校验和(第 17 篇)加入时本机发 1 个成员报告,离开时发 1 个 Leave(没有看到重复发送)。成员关系用于让交换机 / 路由器只把这个组的流量转给需要的端口。
180 秒共抓到 79 个 IGMP 报文:IGMPv2 报告 79 本机发出 0 个,别的设备发出 79 个(只统计个数) 180 秒里没有抓到任何成员查询——这个网段上可能没有 IGMP 查询者,或者间隔比 180 秒长 netstat 累计的变化(180 秒):收到 IGMP 报文 +79,V1/V2 成员查询 +0,成员报告 +79,本机发出的成员报告 +0
查询者定期发 General Query,主机在最大响应时间内随机延迟回应。本次 180 秒没有听到查询;累计计数说明以前有。
79 个 IGMPv2 报告来自 27 个不同的源地址,涉及 1 个不同的组;TTL 取值 [1];校验和正确的 79 / 79;IP 头长度取值 [24] 字节(24 = 带 Router Alert 选项);最大响应时间字段(报告里恒为 0)取值 [0] 按组统计:224.0.0.251(mDNS) 79 IGMPv2 报告的 IP 目的地址就是被报告的那个组(79 / 79 个符合);所以同一个组里的其它成员也能收到它——这就是“报告抑制”的基础:听到别人已经报告了同一个组,自己就不再发
别的设备在没有查询的情况下也持续发 mDNS 组的报告,27 个设备 180 秒发了 79 个,没有看到“抑制”的效果。