我们有一个远程站点,其中 Mac 没有响应IGMP 成员资格查询,但 Windows 机器确实有响应。因此,大约 10 分钟后,支持 IGMP 的网络交换机会切断发往 Mac 的多播流。
以下是显示该问题的 Wireshark 屏幕截图:
第一个数据包是应用程序请求网络开始允许来自 239.255.20.1 的 IGMP 数据包通过 Mac。然后你会看到,此后大约每 125 秒,配置为 IGMP 查询器 (10.1.254.254) 的网络交换机就会询问我们是否仍然对该流感兴趣。注意明显缺乏响应。
为了进行比较,以下是在本地网络上发生的情况:
这里,大约每 95 秒 IGMP 查询器 (172.20.0.2) 会询问我们是否仍然需要该流,而相关的 Mac (172.20.0.144) 则会说“是的,继续发送”。
有问题的 Mac 上的防火墙在 GUI 中已关闭,并且我在命令行中已验证了这一点:
$ /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate 防火墙已禁用。(状态 = 0) $ /usr/libexec/ApplicationFirewall/socketfilterfw --getblockall 封锁所有已禁用! $ /usr/libexec/ApplicationFirewall/socketfilterfw --getstealthmode 隐身模式已禁用 $ /usr/libexec/ApplicationFirewall/socketfilterfw --getappblocked /Applications/mumblemutter.app/... 该应用程序不属于防火墙的一部分
该应用程序并不重要,因为堆栈在加入组后处理 IGMP 查询。
有问题的 Mac 运行的是 10.11.5,但我不相信升级到最新版本就能解决这个问题,因为这意味着基于 BSD 的操作系统在 2016 年修复了其网络堆栈中的严重错误。有可能,但概率极低。
答案1
问题显示在第一个数据包捕获中,您会注意到 IGMP 组加入数据包是 IGMPv2 数据包,但来自 IGMP 查询器的响应都是 v3。
这看起来不错,因为 macOS 已经支持 IGMPv3 很长时间了,但如果你深入研究Darwin 开源内核中的 IGMP 实现在 中igmp_input_v3_query()
,你会发现这段有启发性的代码:
/*
* Discard the v3 query if we're in Compatibility Mode.
* The RFC is not obviously worded that hosts need to stay in
* compatibility mode until the Old Version Querier Present
* timer expires.
*/
if (igi->igi_version != IGMP_VERSION_3) {
...etc...
这意味着 macOS 正在遵循IGMPv3 规范并将任何已看到 IGMPv2 数据包的网络接口置于“兼容模式”,这意味着它既不会确认 IGMPv3 数据包,也不会在该网络接口上使用 IGMPv3。就上面的代码而言,它将接口标记为igi_version = 2
,因此我们将进行此测试并忽略 v3 组成员身份查询,因为理论上在这个网络上使用 v3 是不安全的,以免 v2 设备无法理解发生了什么。
我认为有三种可行的补救措施:
让网络负责人重新配置他们的交换机,以便将 IGMPv2 查询发送回请求 IGMPv2 组加入的客户端。
完全关闭支持 IGMP 的网络交换机中的 IGMPv3 支持,以便它们只发送 IGMPv2 成员资格查询。
监控网络中的 IGMPv2 数据包,找到其来源,并修复、升级或删除它们。如果网络无法完全支持 v3,则选择 #1 或 #2。
这不是你可以通过更改应用程序代码来解决的问题。IP_ADD_MEMBERSHIP
选项到setsockopt()
不包含版本号,因此应用程序无法要求 IGMPv3。该决定由堆栈决定。
虽然有可能有一个操作系统设置会影响这一点,但只有当 macOS IGMP 实现与我们在igmp.c
上面的链接中看到的不同时才会出现这种情况。
如果您在 Windows 机器上嗅探网络中的 IGMP,您将看到它使用 v3 响应来响应 IGMPv3 成员资格查询,尽管网络上存在 v2。因此,这违反了 RFC;虽然有些网络管理员会说,“嗯,它有效,不是吗?”,但正确的回应一定是,因为您无法强迫 macOS 也忽略 RFC,所以解决方案仍然是修复网络。
答案2
这基本上会永久破坏大多数网络上的 IGMPv3。为什么?因为一些非常常见的 mDNS 实现(如 iPhone)经常无故离开并重新加入 224.0.0.251(mDNS 组),速度比 IGMP 版本超时更快。即使只有一个设备发出 224.0.0.251 的 IGMPv2 离开,查询器也会发出 224.0.0.251 的组特定 ICMPv2 查询,以查看是否有人离开。该组中的其他人(如今大多数主机都是这样)都会看到它并将接口切换为 v2,从而使 MacOS 永远无法回答 IGMPv3 查询。
尽管 IGMP 规范规定主机不应明确离开和加入 224.0.0.0/24 块,并且监听交换机应始终转发它,但这一切仍然发生了。祝愿 Apple 能在其无数设备上修复这个无端离开/加入问题。
您可以通过在将查询器切换到 IGMPv3 后重新启动所有 iOS 设备并等待来解决此问题。但如果任何设备发出 IGMPv2 消息,MacOS 多播将再次中断。
这是一个明显的错误,只能怪 MacOS 在认为某个接口是 v2 时忽略了 IGMPv3 消息。