Меню

Captive portal своими руками

Captive Portal для самых маленьких

Здравствуйте мои маленькие любители авиационного спирта =) !

Последние пару дней занимался настройкой Wi-Fi, да не простого, а стильного-модного-молодёжного, со своим Captive Portal. Для тех, кто в танке: это когда ты подключаешься к Wi-Fi сети, но прежде чем допускать тебя к интернетам и ЛОРу в частности, нужно пройти какую-никакую дополнительную авторизацию на веб-страничке, third-party так сказать.

Такой подход я считаю более секурным, потому как, доступ каждого клиента по Wi-Fi регулируется лично через iptables, а не тупо форвардится всё подряд. Какой простор для творчества! Во-вторых, авторизация происходит через веб-страничку, а не WPA и прочие нативные механизмы wireless-сетей, которые как и всё в нашем мире, не вечны и надёжность их хромает.

После вступления, приступим.

Рассказывать о настройке NAT лишний раз не буду, думаю, у вас уже должна быть настроена раздача Wi-Fi, и всё, что вам ненужно, это только Captive Portal.

wlan0 — имя интерфейса Wi-Fi
eth0 — имя интерфейса с интернетами
192.168.0.0/24 — локалка

Вот и всё. Здесь включена проверка через -i wlan0, таким образом это не вызовет никаких конфликтов с другими сетями, т.к. у меня в продакшене под кроватью очень много правил iptables и я знаю, о чём говорю.

Подводные камни, на которые я наткнулся и спешу поделиться с вами. В соседнем треде мне научно-популярно объяснили, что тщетно пытаться настроить редирект по HTTPS на свой Captive Portal, это просто не сработает, это уже MitM атака. Не очень-то и хотелось! ;p

Если у вас используются личные DNS, то наверняка у вас есть правило, разрешающее локальные запросы к серверу (tcp/53 udp/53). Не забудьте разрешить запросы и к локальному веб-серверу (tcp/80). Но а если вы сообщаете Wi-Fi клиентам какие-то публичные NS, то не забудьте разрешить доступ клиентам к ним: iptables -t filter -I FORWARD -i wlan0 -s 192.168.0.0/24 -d 8.8.8.8/32 -j ACCEPT . А суть такова. Когда клиент подключается к Wi-Fi, он проверяет доступность интернета в целом, для этого смартфоны качают со своих серверов файлы и проверяют корректность полученных данных. Если оно не сможет резолвить хост запрашиваемого сайта, то на этом и споткнётся и проверка на наличие Captive Portal в сети не пройдёт.

Собственно, теперь к механизму Captive Portal.

Как уже замечено, это личная прерогатива каждого клиента, проверять доступность интернета, и если в результате проверки что-то пошло не так, — значит либо интернета нет, либо Captive Portal.

Мы перенаправили все запросы на 80 порт к себе, на свой локальный сервер. Теперь nginx должен в ответ на все HTTP запросы отвечать кодом 302. Не 200, не 301, не 511, а именно 302, а затем перенаправлять вас на страничку с third-party авторизацией, и только таким макаром например мой Андрюша-9 смог обнаружить, что у меня таки Captive Portal, а не какой-то сломанный интернет. В результате сразу после подключения к Wi-Fi сети должно появиться Push-уведомление: Скриншот #1, при нажатии которого откроется страничка, куда редиректит nginx Скриншот #2.

Сам скрипт странички я оставляю вам на откуп: думаю, вам не составит никакого труда наслюнявить однострочник на php добавляющий $_SERVER[‘REMOTE_ADDR’] в iptables через shell_exec(); или типа того. Да? Да. Ваш Captive Portal полностью в ваших руках.

Вот и весь механизм работы Captive Portal. Спрашивайте ответы.

Источник

Wi-Fi в кафе, авторизация по смс своими руками и почти бесплатно

Wi-Fi в кафе, авторизация по смс своими руками и почти бесплатно

Задача сделать авторизацию по смс посетителей, использующих наш бесплатный Wi-Fi. Это требование закона. Кстати технология называется captive portal.

Уже существует множество решений этой задачи. Из бесплатных привлекательно выглядит Captive Portal service with SMS auth for pfsense. pfSense основан на ядре FreeBSD, но не требует каких-либо знаний и умений, специфичных для данной ОС. Практически весь функционал доступен через веб-интерфейс.

Я же делал свой captive portal на основе заметки Ника Поповича (Pipefish) «Captive Audience». Она была написана ровно пять лет назад, но пока я ничего проще не нашел.

Собрал старенький комп с двумя сетевыми картами. На него поставил Linux Debian 8. Он будет выполнять роль маршрутизатора.

На компе поднял DHCP, DNS, MySQL, Apache.

Основой captive portal будет цепочка правил netfilter/iptables, в которой все пакеты маркируются, перенаправляются на страницу авторизации, где mac посетителя добавляется в исключения.

export IPT=»iptables»
export WAN=ppp+ # Интерфейс, который смотрит в интернет, на нем поднято PPPoE до провайдера
export LAN=eth0 # Локальная сеть
export LAN_IP_RANGE=192.168.37.0/24

$IPT -N internet -t mangle
$IPT -t mangle -A PREROUTING -i $LAN -j internet
#/var/lib/users — файл с исключениями из цепочки пакетов от авторизованных mac’ов:
#iptables -t mangle -I internet 1 -m mac —mac-source $mac -j RETURN
/var/lib/users
$IPT -t mangle -A internet -j MARK —set-mark 99
$IPT -t nat -A PREROUTING -i $LAN -p tcp -m mark —mark 99 -m tcp —dport 80 -j DNAT —to-destination $INT_IP
$IPT -t filter -A INPUT -p tcp —dport 80 -j ACCEPT
$IPT -t filter -A INPUT -p udp —dport 53 -j ACCEPT
$IPT -t filter -A INPUT -m mark —mark 99 -j DROP
$IPT -A INPUT -p all -m state —state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -p all -m state —state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -t nat -A POSTROUTING -o $WAN -s $LAN_IP_RANGE -j MASQUERADE

Ему нужно задать права

Читайте также:  Водопады гроты своими руками

sudo chmod 700 /etc/firewall.sh

А чтобы он сам запускался при загрузке, нужно вписать в /etc/ rc.local

/etc/firewall.sh

Запретить консоль пользователю www-data:

usermod -s /bin/ false www-data

Сделать apache владельцем файла /var/lib/users и дать права на чтение/запись. В этом файле хранятся все mac’и авторизованных посетителей.

chown www-data /var/lib/users
chmod 600 /var/lib/users

Задать разрешения для apache добавлением в /etc/sudoers строк

www-data ALL=(ALL:ALL) NOPASSWD:/var/lib/users

То же самое для файла /var/lib/user1. В него пишется текущий mac (хотя безопасней не писать его в файл, а сразу поручить апачу выполнять «sudo iptables -I internet 1 -t mangle -m mac —mac-source $mac -j RETURN«). Тем самым маркированный пакет покинет цепочку «interenet».

Туда же добавить строку (чтобы апач смог определить mac посетителя):

www-data ALL=(ALL:ALL) NOPASSWD:/usr/sbin/arp

Теперь страница авторизации. Коротко на ней происходит следующее:

У посетителя, чьего mac’а нет в базе, спрашиваем номер телефона, посылаем смс с кодом, и после того, как он его введет, добавляем mac в базу и в файлы /var/lib/user и /var/lib/user1. Последний исполняем, а посетителя отправляем на запрашиваемый изначально url.

Как вариант, можно обойтись без файла исключений /var/lib/user, а при каждом новом подключении проверять mac на наличие в базе. Плюс писать какое-нибудь приветствие. С файлом исключений посетитель, чей mac там есть, сразу попадет в интернет. Количество правил в iptables будет чуть больше количество авторизованных mac-ов. Максимальное их количество ограничено 65536 и зависит от оперативки. Но на производительность оно вряд-ли влияет

В итоге на точках доступа открытая Wi-Fi сеть. При запросе любой страницы в браузере посетитель получает страницу авторизации. После ввода кода, его mac-адрес добавляется в исключения цепочки «internet», записывается в базу и файл исключений, с тем чтобы при следующем подключении ходить в интернет без авторизации. В базе хранится список номеров телефонов и mac’ов устройств посетителей.

Шейпинг трафика реализован посредством htb.

Комп кроме маршрутизатора еще выполняет роль принт-сервера. Также по расписанию перегружает точки доступа.

Год спустя в кафе открыли второй зал, и посетители стали грузить CPU почти на 100%. Тогда же мне в руки попал Mikrotik. На нем вариантов организовать авторизацию несколько, но я решил пойти по протоптанному пути. Благо в Mikrotik стоит RouterOS и используются те же iptables. Конечно, такой вариант бесплатным уже не назовешь, но зато Mikrotik со своими девятью ядрами, по 1.2 ГГц на ядро держит гораздо большую нагрузку.

Итак, дописал страницу авторизации следующим образом (заменил соответствующие функции):

//функция выполнения команд на микротике (подключаемся по ssh, используя ключ)

function ssh_exec($ip, $command) <
$connection = ssh2_connect($ip, 22);
if (ssh2_auth_pubkey_file($connection, ‘www-data’, ‘/var/www/.ssh/id_rsa.pub’, ‘/var/www/.ssh/id_rsa’)) <
$stream = ssh2_exec($connection, $command);
stream_set_blocking($stream, true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
return stream_get_contents($stream_out);
fclose($stream);
> else <
die(‘Public Key Authentication Failed’);
>>

//узнаем мак из таблицы ARP

$string=’:global mac; :foreach a in=[/ip arp find where address=’.$ip.’ dynamic=yes ] do=<:set mac [/ip arp get $a mac-address ]; :put $mac;>’;
$mac = ssh_exec($router, $string);
preg_match(‘/. /’,$mac , $matches);
@$mac = $matches[0];

//отправляем смс с 3G-модема, воткнутого в микротик

$string=’/tool sms send usb3 channel=3 +7′.$tel.’ message=»Ваш код WiFi: ‘.$code.’»‘;
ssh_exec($router, $string);

//или с модема, воткнутого в комп, например, с помощью gnokii (меньше заморочек с кириллицей)

$sms = «Ваш код WiFi: «.$code;
$sms = str_replace(‘ ‘, ‘\ ‘, $sms);
$sms = system(«sudo -u www-data /var/www/html/sms-send.sh +7″.$tel.» «.$sms);

LANG=»ru_RU.UTF-8″
tel=$1
sms=$2
echo «$sms» | /usr/bin/sudo /usr/bin/gnokii —config /etc/sms.conf —sendsms «$tel»

//сначала я отправлял смс через сервис smsc.ru

Но, с увеличением количества клиентов, это стало не выгодно. Тем более, что в кафе работает онлайн-заказ обедов (respublica-omsk.ru/online/), и гости любят ставить галочку «прислать смс с заказом». Плюс уведомления при онлайн-покупке билетов на мероприятия.

//далее добавляем в микротик правило перепрыгивать маркировку пакетов для данного mac’а

$string=’/ip firewall mangle add chain=prerouting src-mac-address=»‘.$mac.’» in-interface=BRIDGE protocol=tcp action=jump jump-target=registry place-before=0’;
ssh_exec($router, $string);

Настройку файерволла микротика пока не буду описывать. Она аналогична настройке в debian. Если не согласны — пишите в комменты. Буду рад ответить.

Источник

Распределённый Captive Portal в публичных местах и сложности с Apple

Почитав про метро, хотел было комментировать, но решил написать отдельно.

Мы участвовали в создании публичных сетей с распределёнными 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à — вот он интернет. Ваш смартфон сеть запомнил и во время вашего следующего визита подключился к ней уже автоматически. Но хозяева забыли заплатить провайдеру и на этот раз дальше роутера вас не пустили. То есть вы ничего не делали, даже не брали в руки телефон, но, сами того не подозревая, оказались без связи с внешним миром. Это очень плохо. Чтобы этого избежать, современные мобильные устройства выполняют при подключении некий многоступенчатый процесс, цель которого — не оставить вас без связи:

  1. Не можем получить IP — отключаемся
  2. Не видим ARP с default gateway — отключаемся
  3. Не отвечает ни один DNS из списка — отключаемся
  4. Запрашиваем некий url с одного из своих доменов — надеемся увидеть

В случае успеха последнего шага предполагаем, что интернет есть и слезаем с 3G. И так делаем при каждом подключении к wifi. Даже дома.
Если вместо «Success» наблюдаем что-то не то — вот он captive portal. Пора запускать минибраузер. Не смог пользователь за один раз договориться с порталом в окошке — отключаемся. Проблема с айфоном состоит в том, что он до последнего надеется на лучшее. Если вы просите подключиться к сети, и её видно на более, чем одной точке — будут перепробованы все варианты. Убьётся время. Большинство устройств, увидев портал, предполагают, что он тут везде, наверное.

Единственная возможность прекратить метания — выполнить обход обнаружения портала. Возможно осуществить двумя способами — фильтрацией «User-Agent: CaptiveNetworkSupport» или пропускать трафик по некоторому списку доменов. В метро, например, работает iMessage при закрытом портале.

В результате обхода портала сеть видно либо никак либо не всю. В любом случае, это — очень плохо, потому что, фактически оставляет пользователя без связи незаметным для него образом.

На нашем оборудовании обнаружение выключается одной командой:

Источник

Adblock
detector