Почитав про метро, хотел было комментировать, но решил написать отдельно.
Мы участвовали в создании публичных сетей с распределёнными captive portal и наступали практически на все грабли, поэтому хочу поделиться опытом.
Для начала — немного теории о том, как это работает и чем распределённые порталы отличаются от централизованных. Идеологически то, что мы привыкли называть Captive Portal, на самом деле состоит из трёх компонентов:
web frontend — предназначен для взаимодействия с пользователем, сбора информации методом заполнения форм и показа ему рекламы. Если мы собираемся просить пользователя вводить личную информацию и пароли, то следует использовать https, соответственно, на сервер нужен нормальный сертификат. Если собираемся просить поставить галочку под соглашением пользователя, то достаточно http.
собственно captive portal — это некий агент, призванный получать информацию, собранную с помощью web frontend, анализировать её, возможно делать от своего имени уточняющие запросы (например, в RADIUS) и по результатам сообщать о своём решении либо непосредственно пользователю, либо ему же посредством web frontend. В случае положительного решения captvie portal приоткрывает для данного пользователя необходимые отверстия в firewall. По истечении заданного промежутка времени отверстия закрываются и мы имеем пользователя обратно в web frontend. Досрочно портал закрывается по неактивности пользователя. Зачастую единственной причиной ограничения времени сессии является желание снова показать пользователю рекламу (если мы не хотим выступать как в метро, уродуя дизайн других сайтов)
firewall — ведает доступом отдельных пользователей в сеть. В случае отсутствия доступа по идейным соображениям — выполняет перенаправление пользователя в web frontend. В случае отсутствия доступа по техническим причинам (не пингуется gateway) можно поручить firewall выполнять перенаправление пользователя на специальную страничку «сервиса нет, но мы чиним изо всех сил».
В случае централизованного captive portal все три компонента очевидным образом располагаются на одной машине (устройстве), что сильно упрощает задачу. Firewall в данном случае часто исполняет ещё и NAT, а captive portal можно реализовать в виде кучки скриптов, которые подкручивают локальный iptables. Возникает труднопреодолимое желание натолкать в сеть дешёвых точек доступа, которые свалят нам всех пользователей в ethernet или в самом лучшем случае — в отдельный vlan. Какие здесь проблемы:
Как вы уже догадываетесь, распределённый captive portal призван решать все эти проблемы. Говоря «распределённый», мы предполагаем, что компоненты могут размещаться на разных устройствах. Это позволит нам создать надёжную систему, которая обеспечит нужный уровень безопасности и сервиса, при этом обладая большими возможностями по масштабированию. Проблему, которую нам предстоит решить — обеспечить взаимодействие между компонентами captive portal. Где же следует располагаться компонентам решения?
Firewall должен находиться максимально близко к клиенту, т.е. однозначно в точке доступа. Поскольку точек доступа несколько и в каждой из них — свой firewall, то их работа должна быть синхронизирована в рамках некоторого пространства или местности, в пределах которой предполагается роуминг клиентов. В противном случае клиенты при роуминге будут испытывать проблемы с коммуникацией. В современных сетях задача синхронизации работы чего-либо внутри некой области (RF-домена) выполняется с помощью назначаемых арбитров (менеджеров RF-домена) и была решена в стародавние времена безотносительно к задаче реализации распределённого captive portal. Для этой системы синхронизация работы firewall — просто ещё один из процессов, который должен выполняться в домене согласованно, наряду (например) с коммутацией трафика, синхронизацией конфигураций точек или сбором статистики.
Место расположения web frontend сильно зависит от сложности задач, которые ему предстоит решать. Если надо показывать странички, не предполагающие server side processing или каких-то сложностей типа рассылки СМС, то вполне можно обойтись сервером на точке доступа. Он, опять же, располагается максимально близко к клиенту и обеспечивает наиболее эффективное с ним взаимодействие. Синхронизацией контента веб серверов на разных точках доступа займётся (сюрприз) менеджер RF-домена.
Место расположения captive portal зависит от положения web frontend и доступности точек. Поскольку задачей captive portal является подкручивание firewall, то он должен иметь своё представительство (агента) на каждой точке. Тем не менее, web frontend может коммуницировать с любой из копий этих агентов, ибо их состояние (вы уже догадались) также синхронизируется в рамках домена.
Таким образом, мы добиваемся ситуации, при которой для клиента, успешно прошедшего авторизацию, captive portal открывается сразу во всём домене и после этого в любой момент на всех точках доступа домена firewall для этого клиента настроен одинаково.
Метод взаимодействия с captive portal. Нам нужен механизм, с помощью которого мы можем сообщить порталу результаты взаимодействия с пользователем. В нашем случае в качестве такого механизма был выбран HTTP GET. При необходимости приоткрыть портал мы посылаем HTTP GET в любое из его представительств. Состав передаваемых в GET параметров зависит от режима, в котором работает портал. Здесь несколько вариантов:
Всё, что за пределами этой логики, требует реализации в web frontend. Например, можно спросить у пользователя телефон, послать ему смс, проверить код. По результатам — зарядить в радиус пользователя (например) с username=номер_телефона и password=его_IP и дальше послать GET в портал с этими значениями.
Как портал, получив GET, разбирается о каком пользователе идёт речь? При переадресации пользователя в web frontend портал приделывает к вызову довольно длинную переменную, которую мы должны вернуть ему в неприкосновенности среди параметров запроса на открытие портала.
В идеале, точка выполняет бриджинг (форвардинг 2-го уровня) между SSID и неким vlan в проводах. То есть firewall работает на втором (MAC) уровне. Поскольку firewall видит прилетевший из недр вашей сети DHCP offer клиенту, он точно знает его IP, сам отвечает вместо клиента на ARP и жёстко фильтрует весь ARP и DHCP на беспроводном сегменте.
Отсутствие у точки IP-адреса в пользовательском vlan исключает возможность коммуникации пользователя непосредственно с точкой. Однако, иногда нам такая возможность необходима — при расположении web и портала прям на точке. В этом случае используется фиктивный адрес 1.1.1.1
И почему мы везде, как и в метро, убеждаем айфончеги, что портала нет.
По тому, как айфончики ведут себя в беспроводных сетях, у меня сложилось стойкое убеждение, что создатели этого мегапродукта предполагали только один сценарий, а именно — одна точка доступа. То есть либо дома, либо в кафе для хипстеров. Во втором случае есть неиллюзорный шанс встретиться с captive portal.
Что предпринимает айфончик, встретив несколько точек с одним SSID и captive portal? Он пробует все доступные. На каждой он подключается, просит адрес, проверяет рандомный url из своего длинного списка (раньше он был один), понимает, что тут captive, отдаёт адрес (dhcp release) и отключается. Поскольку в нашем случае один SSID светит с каждой точки и в 2.4 и в 5GHz, всё умножается на два. Придя к логичному заключению «да тут везде засада!», айфончик снова подключается к одной из точек и рисует свой минибраузер. В терминологии наших заказчиков и клиентов этот процесс называется «Мой последний айфон очень долго подключается к вашей сети» и «у меня дома всё летает на точке за 1000 р.» В случае скоординированной сети (не отдельных точек) при каждом подключении точка посылает сообщение менеджеру домена «у нас новый пассажир», а в случае MESH — параллельно ещё и туда. Весь процесс занимает до 20 секунд.
Что предпринимает айфончик, встретив одинаковый SSID сразу в 2.4 и в 5GHz? Вы думали, что сможете балансировать клиентов между каналами, точками и диапазонами, максимально используя возможности клиентов и пропускание сети? Только не с продуктами Apple! Со стороны сети, слыша от клиента запросы в обоих диапазонах, мы вправе предполагать, что сможем вынудить клиента подключиться куда нам надо, пропуская запросы к тем точкам, куда мы не хотим, чтобы он подключался. Обычно клиенты понимают намёк и подключаются, например, в 5Ghz. Айфон будет ломиться в 2.4 до последнего. Для упорных есть отдельный счётчик (20 запросов подряд по умолчанию). Тоже занимает время.
Два описанных процесса происходят не только при подключении к сети, но и при роуминге, если отойти достаточно далеко. О, да здесь новые точки. Ну-ка, проверим…
Что предпринимает айфончик, если он запустил минибраузер и нам (вдруг) надо прислать клиенту СМС? Он показывает смс в маленьком окошке сверху с временем экспозиции порядка 3 секунд. Блондинка не в состоянии за это время запомнить 6 (шесть!) цифр. Окошко уезжает, пользователь тычет пальчиком в смс, минибраузер закрывается, dhcp release, disconnect, welcome to 3G. Пользователь с горем пополам запоминает код, лезет в settings, подключается к сети, введите номер телефона, получите новый смс. И далее, и далее… В терминологии заказчиков и пользователей это называется «на моём последнем айфоне не работает ваш каптив портал» и «даже в метро уже починили».
Ситуацию можно поправить, пересылая в web frontend MAC пользователя (мы умеем), запоминать там, что мы ему уже посылали смс и при втором заходе спрашивать уже код. Ибо куки этот минибраузер не поддерживает.
В чём причина такого малоадекватного поведения? Всё просто: создатели прибора ставили целью не оставить вас без связи.
Предположим, вы пришли в гости. Там — закрытая сеть, но добрые хозяева сообщили вам пароль и voilà — вот он интернет. Ваш смартфон сеть запомнил и во время вашего следующего визита подключился к ней уже автоматически. Но хозяева забыли заплатить провайдеру и на этот раз дальше роутера вас не пустили. То есть вы ничего не делали, даже не брали в руки телефон, но, сами того не подозревая, оказались без связи с внешним миром. Это очень плохо. Чтобы этого избежать, современные мобильные устройства выполняют при подключении некий многоступенчатый процесс, цель которого — не оставить вас без связи:
В случае успеха последнего шага предполагаем, что интернет есть и слезаем с 3G. И так делаем при каждом подключении к wifi. Даже дома.
Если вместо «Success» наблюдаем что-то не то — вот он captive portal. Пора запускать минибраузер. Не смог пользователь за один раз договориться с порталом в окошке — отключаемся. Проблема с айфоном состоит в том, что он до последнего надеется на лучшее. Если вы просите подключиться к сети, и её видно на более, чем одной точке — будут перепробованы все варианты. Убьётся время. Большинство устройств, увидев портал, предполагают, что он тут везде, наверное.
Единственная возможность прекратить метания — выполнить обход обнаружения портала. Возможно осуществить двумя способами — фильтрацией «User-Agent: CaptiveNetworkSupport» или пропускать трафик по некоторому списку доменов. В метро, например, работает iMessage при закрытом портале.
В результате обхода портала сеть видно либо никак либо не всю. В любом случае, это — очень плохо, потому что, фактически оставляет пользователя без связи незаметным для него образом.
На нашем оборудовании обнаружение выключается одной командой:
Мы участвовали в создании публичных сетей с распределёнными captive portal и наступали практически на все грабли, поэтому хочу поделиться опытом.
Для начала — немного теории о том, как это работает и чем распределённые порталы отличаются от централизованных. Идеологически то, что мы привыкли называть Captive Portal, на самом деле состоит из трёх компонентов:
web frontend — предназначен для взаимодействия с пользователем, сбора информации методом заполнения форм и показа ему рекламы. Если мы собираемся просить пользователя вводить личную информацию и пароли, то следует использовать https, соответственно, на сервер нужен нормальный сертификат. Если собираемся просить поставить галочку под соглашением пользователя, то достаточно http.
собственно captive portal — это некий агент, призванный получать информацию, собранную с помощью web frontend, анализировать её, возможно делать от своего имени уточняющие запросы (например, в RADIUS) и по результатам сообщать о своём решении либо непосредственно пользователю, либо ему же посредством web frontend. В случае положительного решения captvie portal приоткрывает для данного пользователя необходимые отверстия в firewall. По истечении заданного промежутка времени отверстия закрываются и мы имеем пользователя обратно в web frontend. Досрочно портал закрывается по неактивности пользователя. Зачастую единственной причиной ограничения времени сессии является желание снова показать пользователю рекламу (если мы не хотим выступать как в метро, уродуя дизайн других сайтов)
firewall — ведает доступом отдельных пользователей в сеть. В случае отсутствия доступа по идейным соображениям — выполняет перенаправление пользователя в web frontend. В случае отсутствия доступа по техническим причинам (не пингуется gateway) можно поручить firewall выполнять перенаправление пользователя на специальную страничку «сервиса нет, но мы чиним изо всех сил».
В случае централизованного captive portal все три компонента очевидным образом располагаются на одной машине (устройстве), что сильно упрощает задачу. Firewall в данном случае часто исполняет ещё и NAT, а captive portal можно реализовать в виде кучки скриптов, которые подкручивают локальный iptables. Возникает труднопреодолимое желание натолкать в сеть дешёвых точек доступа, которые свалят нам всех пользователей в ethernet или в самом лучшем случае — в отдельный vlan. Какие здесь проблемы:
- Проблемы с безопасностью. Мы ограничиваем доступ к внешнему каналу, однако в локальной сети всё плохо. Поскольку сеть открытая, любой пользователь может отвечать на arp от имени нашего default gateway, получать трафик пользователей и заниматься фишингом. Не возбраняется поставить свой сервер DHCP и в некой дельта-окрестности стремать пользователей заявлениями типа «ваш браузер безнадёжно устарел». Если ваш captive portal и пользователя разделяет роутер, то у вас нет возможности контролировать на captive portal соответствие mac и ip со всеми вытекающими. Коммуникация между беспроводными клиентами становится возможной. Вы можете на дешёвой точке запретить коммуницировать беспроводным клиентам, но клиенты других точек видны уже по ethernet.
- Проблемы с трафиком. Имеем в локальной сети много лишнего трафика. Желательно до открытия captive portal клиентов дальше точки доступа не пускать.
- Проблемы с масштабируемостью. При большом числе клиентов проблемным может стать любой из трёх компонентов портала.
Как вы уже догадываетесь, распределённый captive portal призван решать все эти проблемы. Говоря «распределённый», мы предполагаем, что компоненты могут размещаться на разных устройствах. Это позволит нам создать надёжную систему, которая обеспечит нужный уровень безопасности и сервиса, при этом обладая большими возможностями по масштабированию. Проблему, которую нам предстоит решить — обеспечить взаимодействие между компонентами captive portal. Где же следует располагаться компонентам решения?
Firewall должен находиться максимально близко к клиенту, т.е. однозначно в точке доступа. Поскольку точек доступа несколько и в каждой из них — свой firewall, то их работа должна быть синхронизирована в рамках некоторого пространства или местности, в пределах которой предполагается роуминг клиентов. В противном случае клиенты при роуминге будут испытывать проблемы с коммуникацией. В современных сетях задача синхронизации работы чего-либо внутри некой области (RF-домена) выполняется с помощью назначаемых арбитров (менеджеров RF-домена) и была решена в стародавние времена безотносительно к задаче реализации распределённого captive portal. Для этой системы синхронизация работы firewall — просто ещё один из процессов, который должен выполняться в домене согласованно, наряду (например) с коммутацией трафика, синхронизацией конфигураций точек или сбором статистики.
Место расположения web frontend сильно зависит от сложности задач, которые ему предстоит решать. Если надо показывать странички, не предполагающие server side processing или каких-то сложностей типа рассылки СМС, то вполне можно обойтись сервером на точке доступа. Он, опять же, располагается максимально близко к клиенту и обеспечивает наиболее эффективное с ним взаимодействие. Синхронизацией контента веб серверов на разных точках доступа займётся (сюрприз) менеджер RF-домена.
Место расположения captive portal зависит от положения web frontend и доступности точек. Поскольку задачей captive portal является подкручивание firewall, то он должен иметь своё представительство (агента) на каждой точке. Тем не менее, web frontend может коммуницировать с любой из копий этих агентов, ибо их состояние (вы уже догадались) также синхронизируется в рамках домена.
Таким образом, мы добиваемся ситуации, при которой для клиента, успешно прошедшего авторизацию, captive portal открывается сразу во всём домене и после этого в любой момент на всех точках доступа домена firewall для этого клиента настроен одинаково.
Тонкости
Метод взаимодействия с captive portal. Нам нужен механизм, с помощью которого мы можем сообщить порталу результаты взаимодействия с пользователем. В нашем случае в качестве такого механизма был выбран HTTP GET. При необходимости приоткрыть портал мы посылаем HTTP GET в любое из его представительств. Состав передаваемых в GET параметров зависит от режима, в котором работает портал. Здесь несколько вариантов:
- Портал открывается всегда. Возможно занести запись об этом в log.
- Портал открывается при наличии в GET переменной, отражающей согласие с условиями (agreement).
- В GET передаются username и password, портал сам лезет в RADIUS с этими атрибутами и открывается, получив оттуда ACCEPT.
- В GET передаётся один (универсальный) атрибут, портал указывает его и как username и как password при обращении в RADIUS и открывается, получив ACCEPT. Понятно, что такой пользователь должен быть в RADIUS
Всё, что за пределами этой логики, требует реализации в web frontend. Например, можно спросить у пользователя телефон, послать ему смс, проверить код. По результатам — зарядить в радиус пользователя (например) с username=номер_телефона и password=его_IP и дальше послать GET в портал с этими значениями.
Как портал, получив GET, разбирается о каком пользователе идёт речь? При переадресации пользователя в web frontend портал приделывает к вызову довольно длинную переменную, которую мы должны вернуть ему в неприкосновенности среди параметров запроса на открытие портала.
В идеале, точка выполняет бриджинг (форвардинг 2-го уровня) между SSID и неким vlan в проводах. То есть firewall работает на втором (MAC) уровне. Поскольку firewall видит прилетевший из недр вашей сети DHCP offer клиенту, он точно знает его IP, сам отвечает вместо клиента на ARP и жёстко фильтрует весь ARP и DHCP на беспроводном сегменте.
Отсутствие у точки IP-адреса в пользовательском vlan исключает возможность коммуникации пользователя непосредственно с точкой. Однако, иногда нам такая возможность необходима — при расположении web и портала прям на точке. В этом случае используется фиктивный адрес 1.1.1.1
При чём тут Apple
И почему мы везде, как и в метро, убеждаем айфончеги, что портала нет.
По тому, как айфончики ведут себя в беспроводных сетях, у меня сложилось стойкое убеждение, что создатели этого мегапродукта предполагали только один сценарий, а именно — одна точка доступа. То есть либо дома, либо в кафе для хипстеров. Во втором случае есть неиллюзорный шанс встретиться с captive portal.
Что предпринимает айфончик, встретив несколько точек с одним SSID и captive portal? Он пробует все доступные. На каждой он подключается, просит адрес, проверяет рандомный url из своего длинного списка (раньше он был один), понимает, что тут captive, отдаёт адрес (dhcp release) и отключается. Поскольку в нашем случае один SSID светит с каждой точки и в 2.4 и в 5GHz, всё умножается на два. Придя к логичному заключению «да тут везде засада!», айфончик снова подключается к одной из точек и рисует свой минибраузер. В терминологии наших заказчиков и клиентов этот процесс называется «Мой последний айфон очень долго подключается к вашей сети» и «у меня дома всё летает на точке за 1000 р.» В случае скоординированной сети (не отдельных точек) при каждом подключении точка посылает сообщение менеджеру домена «у нас новый пассажир», а в случае MESH — параллельно ещё и туда. Весь процесс занимает до 20 секунд.
Что предпринимает айфончик, встретив одинаковый SSID сразу в 2.4 и в 5GHz? Вы думали, что сможете балансировать клиентов между каналами, точками и диапазонами, максимально используя возможности клиентов и пропускание сети? Только не с продуктами Apple! Со стороны сети, слыша от клиента запросы в обоих диапазонах, мы вправе предполагать, что сможем вынудить клиента подключиться куда нам надо, пропуская запросы к тем точкам, куда мы не хотим, чтобы он подключался. Обычно клиенты понимают намёк и подключаются, например, в 5Ghz. Айфон будет ломиться в 2.4 до последнего. Для упорных есть отдельный счётчик (20 запросов подряд по умолчанию). Тоже занимает время.
Два описанных процесса происходят не только при подключении к сети, но и при роуминге, если отойти достаточно далеко. О, да здесь новые точки. Ну-ка, проверим…
Что предпринимает айфончик, если он запустил минибраузер и нам (вдруг) надо прислать клиенту СМС? Он показывает смс в маленьком окошке сверху с временем экспозиции порядка 3 секунд. Блондинка не в состоянии за это время запомнить 6 (шесть!) цифр. Окошко уезжает, пользователь тычет пальчиком в смс, минибраузер закрывается, dhcp release, disconnect, welcome to 3G. Пользователь с горем пополам запоминает код, лезет в settings, подключается к сети, введите номер телефона, получите новый смс. И далее, и далее… В терминологии заказчиков и пользователей это называется «на моём последнем айфоне не работает ваш каптив портал» и «даже в метро уже починили».
Ситуацию можно поправить, пересылая в web frontend MAC пользователя (мы умеем), запоминать там, что мы ему уже посылали смс и при втором заходе спрашивать уже код. Ибо куки этот минибраузер не поддерживает.
В чём причина такого малоадекватного поведения? Всё просто: создатели прибора ставили целью не оставить вас без связи.
Предположим, вы пришли в гости. Там — закрытая сеть, но добрые хозяева сообщили вам пароль и voilà — вот он интернет. Ваш смартфон сеть запомнил и во время вашего следующего визита подключился к ней уже автоматически. Но хозяева забыли заплатить провайдеру и на этот раз дальше роутера вас не пустили. То есть вы ничего не делали, даже не брали в руки телефон, но, сами того не подозревая, оказались без связи с внешним миром. Это очень плохо. Чтобы этого избежать, современные мобильные устройства выполняют при подключении некий многоступенчатый процесс, цель которого — не оставить вас без связи:
- Не можем получить IP — отключаемся
- Не видим ARP с default gateway — отключаемся
- Не отвечает ни один DNS из списка — отключаемся
- Запрашиваем некий url с одного из своих доменов — надеемся увидеть
<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>
В случае успеха последнего шага предполагаем, что интернет есть и слезаем с 3G. И так делаем при каждом подключении к wifi. Даже дома.
Если вместо «Success» наблюдаем что-то не то — вот он captive portal. Пора запускать минибраузер. Не смог пользователь за один раз договориться с порталом в окошке — отключаемся. Проблема с айфоном состоит в том, что он до последнего надеется на лучшее. Если вы просите подключиться к сети, и её видно на более, чем одной точке — будут перепробованы все варианты. Убьётся время. Большинство устройств, увидев портал, предполагают, что он тут везде, наверное.
Единственная возможность прекратить метания — выполнить обход обнаружения портала. Возможно осуществить двумя способами — фильтрацией «User-Agent: CaptiveNetworkSupport» или пропускать трафик по некоторому списку доменов. В метро, например, работает iMessage при закрытом портале.
В результате обхода портала сеть видно либо никак либо не всю. В любом случае, это — очень плохо, потому что, фактически оставляет пользователя без связи незаметным для него образом.
На нашем оборудовании обнаружение выключается одной командой:
ap7131-ABCDEF(config-captive-portal-XXXXX)#bypass ?
captive-portal-detection Captive portal detection requests(e.g., Apple
Captive Network Assistant
ap7131-ABCDEF(config-captive-portal-XXXXX)#bypass captive-portal-detection