Собираю инфу по реализации Captive порталов для WiFI сетей. Вот, первая пташка.
Captive portal собственными руками
Каждый из нас подключался к беспроводной сети (аэропорты, кафе и тд) где необходимо согласится с некоторыми условиями или пройти авторизации прежде чем начинать пользоваться интернетом. Такая технология называется captive portal.
В мою задачу входило создать captive portal где каждому пользователю раз в 30 минут будет показываться определенный сайт (реклама), и пока он не нажмет «кнопочку» «далее» интернета не будет.
Для создания нам понадобится: Wifi-точка доступа любая (на практике можно использовать и проводной интернет) Маршрутизатор на любой *nix системе (в моем случае это debian wheezy)
Краткое описание принципа работы Любой пакет пришедший на маршрутизатор маркируем Любой запрос на 80 порт (пакеты уж маркированны) перенаправляем на нужную нам страницу При «авторизации»(нажатии кнопки далее) пользователя добавляем его мак в исключения и разрешаем доступ в интернет Скрипт вычисляет у кого прошел лимит времени и удаляет данного клиента.
У нас имеется маршрутизатор на базе debian, где eth0 — локальная сеть в моем случае (192.168.11.0/24), eth0:1 — интерфейс который смотрит в интернет.
Настройку интерфейсов мы пропустим, это каждый выполнит сам. Сразу перейдем к настройке iptables, я обычно прописываю iptables в rc.local: /etc/rc.local IPTABLES="/sbin/iptables" EBTABLES="/sbin/ebtables" DHCP="67:68" SSH="22" WWW="80"
$IPTABLES -t mangle -F $IPTABLES -F
$IPTABLES -A INPUT -i lo -j ACCEPT
ssh
$IPTABLES -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
разрешаем серверу и клиентам dns гугла
$IPTABLES -A INPUT -s 8.8.8.8 -j ACCEPT $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
создаем правило интернет
$IPTABLES -N internet -t mangle $IPTABLES -t mangle -A PREROUTING -j internet
добавляем разрешенные маки в исключения путем добавления их в Return
awk 'BEGIN { FS="\t"; } { system("$IPTABLES -t mangle -A internet -m mac --mac-source "$4" -j RETURN"); }' /var/lib/users
маркируем все пакеты
$IPTABLES -t mangle -A internet -j MARK --set-mark 99
все маркированные пакеты которые идут на 80 порт отправляем на наш сервер
$IPTABLES -t nat -A PREROUTING -m mark --mark 99 -p tcp --dport 80 -j DNAT --to-destination 192.168.11.38
дроппаем все маркированное
$IPTABLES -t filter -A FORWARD -m mark --mark 99 -j DROP
dns
$IPTABLES -t filter -A INPUT -s 8.8.8.8 -j ACCEPT
http
$IPTABLES -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
port dns
$IPTABLES -t filter -A INPUT -p udp --dport 53 -j ACCEPT
drop
$IPTABLES -t filter -A INPUT -m mark --mark 99 -j DROP echo "1" > /proc/sys/net/ipv4/ip_forward
настройка нат
$IPTABLES -A FORWARD -i eth0 -o eth0:1 -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -i eth0:1 -o eth0 -j ACCEPT $IPTABLES -t nat -A POSTROUTING -o eth0 -j MASQUERADE
На этом конфигурация iptables заканчивается и переходим к странице которую получает пользователь: /var/lib/index.php <?php
$server_name = "192"; $domain_name = "168.11.38"; $site_name = "Wireless Network";
// arp $arp = "/usr/sbin/arp";
// файл где хранятся текущие пользователи $users = "/var/lib/users";
// Check if we've been redirected by firewall to here. // If so redirect to registration address if ($_SERVER['SERVER_NAME']!="$server_name.$domain_name") { header("location:http://$server_name.$domain_name/index.php?add=" .urlencode($_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'])); exit; }
// получаем и добавляем мак пользователя $mac = shell_exec("$arp -a ".$_SERVER['REMOTE_ADDR']); preg_match('/..:..:..:..:..:../',$mac , $matches); @$mac = $matches[0]; if (!isset($mac)) { exit; }
if (!isset($_POST['email']) || !isset($_POST['name'])) { // Name or email address not entered therefore display form ?>
Welcome to
To access the Internet you must first enter your details:
<?php } else { enable_address(); }
function enable_address() {
global $name; global $email; global $mac; global $users;
// время добавления пользователя храним в unixtime file_put_contents($users,$_POST['name'].";".$_POST['email'].";" .$_SERVER['REMOTE_ADDR'].";$mac;".date("U")."\n",FILE_APPEND + LOCK_EX);
// добавляем правило в iptables exec("sudo iptables -I internet 1 -t mangle -m mac --mac-source $mac -j RETURN"); // The following line removes connection tracking for the PC // This clears any previous (incorrect) route info for the redirection exec("sudo rmtrack ".$_SERVER['REMOTE_ADDR']); sleep(1); header("location:http://".$_GET['add']); exit;
}
// Function to print page header function print_header() {
?>
Welcome to "; echo ""; } ?> Данная страница может быть любой, смысл лишь в том, чтобы получить мак пользователя и добавить его в iptables. В текущий момент получилась следующая схема: Iptables автоматически редиректит любой запрос на 80 порт на нашу страницу пользователь вводит свое имя и почту, скрипт php получает мак пользователя и добавляет в iptables правило исключения для этого мака Php скрипт складывает все данные пользователей (имя, почта, время добавления) в файл /var/lib/users Осталось только сделать скрипт который будет: удалять правило из iptables для мака у которого вышло время удалять из файла данные по этому пользователю Так как мои знания в программировании довольно плачевны был написан простенький скрипт на перле: #!/usr/bin/perl $file = "/var/lib/users"; $curtime = time(); # время "бана" 30 минут время в секундах так как считаем потом в unixtime $bantime = 1800; $tmpfile = "out.tmp"; open(my $data, '<', $file) or die "Could not open '$file' $!\n"; while (my $line = <$data>) { chomp $line; (@field) = split(";", $line); #прибавляем время "бана" ко времени когда зашел пользователь (4 поле в нашем случае) получаем время когда нужно удалить пользователя if (defined($exptime)) { undef $exptime; } $result = $field[4]; $exptime = $bantime + $result; # такая коснтрукция потому что перл не хотел прибавлять $field[4] + $bantime # если текущее время больше времени для удаления, удаляем мак и перезаписываем файл if ($curtime > $exptime) { #printf "BINGO\n"; system "iptables -D internet -t mangle -m mac --mac-source $field[3] -j RETURN"; # system "rm /var/lib/users"; } else { printf "$field[3]; $exptime\n"; open SF, ">>$tmpfile"; printf SF "$field[0];$field[1];$field[2];$field[3];$field[4]\n"; close SF; system "mv /root/out.tmp /var/lib/users"; system "chown www-data. $file"; } } > Все, задача выполенна, модифицируя файлик index.php можем показывать пользователю релкаму, смешные видео, заставлять его оставлять свою почту и т.д.