Сетевой стек OS X игнорирует запросы членства IGMP
У нас есть удаленный сайт, на котором компьютеры Mac не отвечают на запросы о членстве в IGMP, но блоки Windows отвечают. Следовательно, примерно через 10 минут сетевой коммутатор с поддержкой IGMP отключает многоадресный поток для компьютеров Mac.
Вот снимок экрана Wireshark, показывающий проблему:
Первый пакет - приложение, запрашивающее, чтобы сеть начала разрешать пакеты IGMP от 239.255.20.1 до Mac. Затем, примерно через каждые 125 секунд, вы видите, что сетевой коммутатор, настроенный как IGMP-запрос (10.1.254.254), спрашивает, не заинтересованы ли мы в этом потоке. Обратите внимание на заметное отсутствие ответа.
Вот что здесь происходит в локальной сети, для сравнения:
Здесь примерно каждые 95 секунд IGMP-запрос (172.20.0.2) спрашивает, хотим ли мы все еще этот поток, а рассматриваемый Mac (172.20.0.144) отвечает: "Да, продолжайте отправлять его".
Брандмауэр отключен на проблемных компьютерах Mac в графическом интерфейсе, и я проверил это в командной строке:
$ / usr / libexec / ApplicationFirewall / socketfilterfw --getglobalstate Брандмауэр отключен. (State = 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 году. Возможно, но крайне низкая вероятность
2 ответа
Проблема показана в первом захвате пакета, где вы заметите, что пакет присоединения группы IGMP является пакетом IGMPv2, но все ответы от запроса IGMP - v3.
Это может показаться хорошим, так как Mac OS X поддерживает IGMPv3 в течение очень долгого времени, но если вы углубитесь в реализацию IGMP в ядре с открытым исходным кодом Darwin, ниже 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...
Это означает, что Mac OS X (или macOS, если хотите) подчиняется спецификации IGMPv3 и переводит любой сетевой интерфейс, где он видел пакеты IGMPv2, в "режим совместимости", что означает, что он не будет ни подтверждать пакеты IGMPv3, ни говорить IGMPv3 на этот сетевой интерфейс. С точки зрения кода выше, он помечает интерфейс как igi_version = 2
Таким образом, мы пройдем этот тест и проигнорируем v3 на запрос о членстве в группе, полагая, что говорить о v3 в этой сети небезопасно, чтобы устройства v2 не могли понять, что происходит.
Я вижу три действенных средства:
Попросите ответственных за сеть на удаленном сайте перенастроить свои коммутаторы для отправки запросов IGMPv2 клиентам, которые запросили присоединение к группе IGMPv2.
Полностью отключите поддержку IGMPv3 в сетевых коммутаторах, поддерживающих IGMP, чтобы они отправляли только запросы о членстве в IGMPv2.
Контролируйте сеть на наличие пакетов IGMPv2, найдите их источник и исправьте, обновите или удалите их. Если сеть не может быть настроена для передачи v3-thru-and-thru, переходите к #1 или #2.
Это нельзя исправить с помощью изменения кода приложения. IP_ADD_MEMBERSHIP
возможность setsockopt()
не содержит номер версии, поэтому приложение не может требовать IGMPv3. Это решение зависит от стека.
Хотя вполне возможно, что существует параметр ОС, который может повлиять на это, это может иметь место только в том случае, если реализация IGMP в Mac OS X отличается от того, что мы видим в igmp.c
ссылка выше.
Если вы прослушиваете сеть для IGMP в окне Windows, вы увидите, что он отвечает на запросы членства IGMPv3 с ответами v3, несмотря на наличие v2 в сети. Следовательно, это является нарушением RFC; в то время как некоторые сетевые администраторы, которые скажут: "Ну, это работает, не так ли?", правильный ответ должен состоять в том, что, поскольку вы не можете заставить OS X также игнорировать RFC, решение остается исправить сеть.
По сути, это навсегда нарушает IGMPv3 в большинстве сетей. Почему? Потому что некоторые очень распространенные реализации mDNS (например, iPhone) часто и безосновательно покидают и повторно присоединяются к 224.0.0.251 (группе mDNS) быстрее, чем тайм-аут версии IGMP. Если хотя бы одно устройство отправляет IGMPv2-выход для 224.0.0.251, запросчик выдаст групповой запрос ICMPv2 для 224.0.0.251, чтобы узнать, остался ли кто-нибудь. Все остальные в этой группе (которой в наши дни является большинство хостов) увидят это и переключят интерфейс на v2, не позволяя MacOS когда-либо отвечать на запросы IGMPv3.
И все это несмотря на то, что спецификация IGMP гласит, что хосты не должны явно выходить из блока 224.0.0.0/24 и присоединяться к нему, а отслеживающие коммутаторы всегда должны его пересылать. И удачи вам в том, чтобы Apple исправила эту необоснованную проблему с выходом/присоединением на миллионах устройств.
Вы можете обойти эту проблему, перезагрузив все ваши устройства iOS после переключения запроса на IGMPv3 и подождав. Но если какое-либо устройство когда-либо выдаст сообщение IGMPv2, многоадресная рассылка MacOS снова прекратится.
Это явная ошибка, в которой нельзя винить что-либо, кроме того, что MacOS игнорирует сообщения IGMPv3, когда считает, что интерфейс имеет версию v2.