Не рассматривается прокидывание кабеля. Рассматривается только активное оборудование и настройка серверной части.
Дано:
Сервер с freebsd, точки доступа UniFi Ap (Ubiquiti Networks), машина с OS Windows.
Задача:
1. Построить беспроводную сеть с авторизацией через web-интерфейс
2. Обеспечить логирование доступа.
Решение.
1. Включаем точки доступа в уже существующую сеть. В эту же сеть выносим машину с OS windows.
2. Производим настройку точек доступа через программу, прилагаемую на диске. Описывать настройки точек доступа не вижу смысла, ибо там все и так ясно.
3. Настраиваем FreeBSD.
Для FreeBSD нам потребуется:
2. Настройка pf:
%www ALL = NOPASSWD : WIFI
#!/bin/sh
in=`/sbin/pfctl -t permgroup -T show | /usr/bin/wc -l`
out=`/sbin/pfctl -t permgroup -T show | /usr/bin/wc -l`
/bin/echo $in
/bin/echo $out
/bin/echo `/usr/bin/uptime | /usr/bin/cut -d, -f1`
/bin/echo authuser
Дано:
Сервер с freebsd, точки доступа UniFi Ap (Ubiquiti Networks), машина с OS Windows.
Задача:
1. Построить беспроводную сеть с авторизацией через web-интерфейс
2. Обеспечить логирование доступа.
Решение.
1. Включаем точки доступа в уже существующую сеть. В эту же сеть выносим машину с OS windows.
2. Производим настройку точек доступа через программу, прилагаемую на диске. Описывать настройки точек доступа не вижу смысла, ибо там все и так ясно.
3. Настраиваем FreeBSD.
Для FreeBSD нам потребуется:
- Пересборка ядра;
- настроить pf;
- написать пару скриптов;
- apache22;
- php5;
- mysql-server;
- isc-dhcpd-server;
- sudo;
- mrtg
device pf
device pflog
options ALTQ
options ALTQ_CBQ # Class Bases Queueing
options ALTQ_RED # Random Early Detection
options ALTQ_RIO # RED In/Out
options ALTQ_HFSC # Hierarchical Packet Scheduler
options ALTQ_CDNR # Traffic conditioner
options ALTQ_PRIQ # Priority Queueing
options ALTQ_NOPCC # Required for SMP build
2. Настройка pf:
table < rfcnets > {10.0.0.0/8, !192.168.1.0/24, 192.168.0.0/16, !172.16.0.0/16, 172.16.0.0/12 }
table < me > { self, 172.16.0.1}
table < permgroup >
# Options: tune the behavior of pf, default values are given.
set timeout { interval 10, frag 30 }
set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
set timeout { tcp.closing 900, tcp.finwait 45, tcp.closed 5 }
set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
set timeout { icmp.first 20, icmp.error 10 }
set timeout { other.first 60, other.single 30, other.multiple 60 }
set timeout { adaptive.start 0, adaptive.end 0 }
set limit { states 10000000, frags 50000 }
set loginterface none
#set optimization normal
set block-policy drop
set require-order yes
set fingerprints "/etc/pf.os"
#set state-policy if-bound
# Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
scrub in all
# Поднимаем nat для всех, кто попал в таблицу permgroup, остальных редиректим на 10.10.0.2 при попытке перехода на любой внешний сайт, для авторизации.
nat on em0 from < permgroup > to any - > em0
rdr on em1 proto tcp from !< permgroup > to any port 80 - > 10.10.0.2
# Разрешаем loopback
pass quick on lo from any to any
# Описываем IN правила
#Запрещаем rfc сети на внешнем интерфейсе
block in quick on em0 from < rfcnets > to any
# Правила для сервисов (я открываю только то, что нужно и для внутренней сети)
# icmp
pass in quick inet proto icmp from any to 10.10.0.2 icmp-type echoreq keep state
# ssh
pass in quick proto tcp from any to 10.10.0.2 port 22 flags S/SA keep state
# http,https
pass in quick proto tcp from any to 10.10.0.2 port {443, 80} flags S/SA keep state
# dns
pass in quick proto {tcp, udp} from any to < me > port domain flags S/SA keep state
# Все остальное к серверу блокируем
block in quick from any to < me >
# Разрешаем доступ в инет для permgroup, при этом логируем доступ
pass in log quick from any to < permgroup >
pass in log quick from < permgroup > to any
# Остальное на вход блокируем
block in quick all
# Правила для OUT
# запрещаем rfc сети на внешнем интерфейсе.
block out quick on em0 from < rfcnets > to any
#Разрешаем все от самого сервера.
pass out quick from < me > to any keep state
# Разрешаем доступ в инет для permgroup, при этом логируем доступ
pass out log quick from any to < permgroup >
pass out log quick from < permgroup > to any
block out quick all
3. Скрипты для управления, администрирования и авторизации:
3.1. Управление сессиями (pf.sh):
#!/bin/sh
/bin/echo `/usr/local/bin/sudo /sbin/pfctl -t permgroup -T $1 $2` >> /usr/home/admin/wifi/w.txt
Скрипт выполняет действия $1 для $2 (опц.) с таблицей permgroup, которая ранее была описана в файле pf.conf.
Пример:
- pf.sh add 10.10.0.1/32 - Добавит запись в таблицу permgroup ip-адрес 10.10.0.1/32;
- pf.sh delete 10.10.0.2/32 - Добавит запись в таблицу permgroup ip-адрес 10.10.0.2/3;2;
- pf.sh show - Выведет список адресов из таблицы permgroup.
3.2. Авторизация клиента:
3.2.1. index.html:
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="MobileOptimized" content="240"/>
<meta name="viewport" content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes, width=240" />
<title></title>
</head>
<body bgcolor="#ffffff">
<form action="valid.php" id="valid" method="post">
<table>
<tr>
<td colspan="2" align="center">
<img src="img/logo_150x40.gif" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
</td>
</tr>
<tr>
<td>
Логин
</td>
<td>
<INPUT type="text" size="15" id="user" name="user" value="" placeholder="Логин">
</td>
</tr>
<tr>
<td>
Пароль:
</td>
<td>
<INPUT type="password" size="15" name="passwd" value="" placeholder="Пароль">
</td>
</tr>
<tr>
<td colspan="2" align="center">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<INPUT style = "width:100%; height:50; font-size: 25pt;" type="submit" value="Вход">
</td>
</tr>
</table>
</body>
</html>
В принципе, стандартная форма авторизации за исключением того, что она адаптирована под мобильные платформы.
3.2.2. valid.php:
<?php
session_start();
error_reporting(E_ALL);
if (!isset($_POST["user"])) {
header("Location: "."index.html");
exit(1);
}
require "config.php";
require "func.php";
date_default_timezone_set('Asia/Yekaterinburg');
$pUser = "";
$pPass = "";
$pIp = "";
$pId = "";
$date = date("Y-m-d H:i:s");
$day = date("Y-m-d 00:00:00");
if (!preg_match ('/[^\w]/', $_POST["user"])) {
$pUser = $_POST["user"];
}
else {
srv_error(1);
}
if (!preg_match ('/[^\w]/', $_POST["passwd"])) {
$pPass = $_POST["passwd"];
}
else {
srv_error(1);
}
$db1 = mysql_connect($db_host1, $db_user1, $db_pass1) or die();
mysql_select_db($db_name1, $db1);
$result1 = mysql_query("SELECT * FROM abonent WHERE username ='$pUser' AND password='$pPass';", $db1);
$db2 = mysql_connect("127.0.0.1", "root", "") or die();
mysql_select_db("wifi", $db2);
$row = mysql_fetch_array($result1, MYSQL_NUM);
if ($row === FALSE) {
accesslog($logfile, $_SERVER["REMOTE_ADDR"], $pUser, $pPass, 1);
srv_error(1);
}
else {
$result2 = mysql_query("SELECT ip FROM log WHERE user ='$pUser' AND dt >= '$day';", $db2);
while(($row = mysql_fetch_array($result2, MYSQL_NUM)) !== FALSE) {
shell_exec("/usr/home/admin/wifi/pf.sh" . " delete " . $row[0] . "/32");
}
shell_exec("/usr/home/admin/wifi/pf.sh" . " add " . $_SERVER["REMOTE_ADDR"] . "/32");
mysql_query("INSERT INTO log (dt, ip, user, passwd, ok) VALUES ('$date', '{$_SERVER["REMOTE_ADDR"]}' ,'$pUser' , '', 1)", $db2) or die();
header("Location: "."http://ya.ru");
}
?>
Скрипт берет данные о логине и пароле из db1, а логирование авторизации ведет в db2.
Скрипт открывает доступ в инет, в случае успешной авторизации. Если есть 2 сессии, то первая открытая сессия будет закрыта.
3.2.3. func.php:
<?php
function srv_error($value) {
if ($value == 1) {
$meta = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta http-equiv=\"refresh\" content=\"15; url=index.html\"><title>Ошибка доступа.</title>";
$msg = "<h1>Не знаю что не правильно вы ввели, но вы не авторизовались.</h1>";
}
if ($value == 2) {
$meta = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta http-equiv=\"refresh\" content=\"15; url=index.html\"><title>Ошибка сервера.</title>";
$msg = "<h1>Внутренняя ошибка сервера.</h1>";
}
echo "<html>
<head>"
. $meta .
"</head>
<body> "
. $msg .
"</body>
</html>";
unset($_SESSION["id"]);
exit(1);
}
function accesslog($file, $ip, $login, $passwd, $flag) {
$date = date("d.m.Y H:i:s");
if ($flag == 0) {
$log = "[" . $date . "] from " . $ip . " " . $login . " " . $passwd . " GRANTED\n";
}
elseif ($flag == 1) {
$log = "[" . $date . "] from " . $ip . " " . $login . " " . $passwd . " DENIED!\n";
}
$fp = fopen($file, 'a+');
fwrite($fp, $log);
fclose($fp);
}
?>
srv_error - функция подставляет сообщение об ошибке (неверный логин/пароль или внутренняя ошибка).
accesslog - функция, которая ведет запись в файл попытки авторизации, сохраняя логин и пароль.
4 и 5.
Apache и php оставляем без изменений. Единственное, что надо сделать, так это установить php5-extentions пакет для того, чтобы php понимал как работать с СУБД.
6. MySQL-server,
Установка mysql сервера проходит в штатном режиме, а вот БД создать придется.
CREATE DATABASE wifi;
CREATE TABLE `log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dt` datetime DEFAULT NULL,
`ip` varchar(32) DEFAULT NULL,
`user` varchar(255) DEFAULT NULL,
`passwd` varchar(255) DEFAULT NULL,
`ok` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1;
Одна единственная таблица в БД.
7. dhcp
Настройка dhcp делается за 2 минуты. Я выдаю ip на 12 часов.
Конфиг:
option domain-name "example.org";
option domain-name-servers ns1.example.org, ns2.example.org;
default-lease-time 43200;
max-lease-time 43201;
log-facility local7;
subnet 10.10.0.0 netmask 255.255.0.0 { range 10.10.228.1 10.10.228.254; option routers 10.10.0.2; option domain-name-servers 10.10.254.253; }
Выделяем ip адреса для этого dhcp из диапазона 10.10.228.0/24, 10.10.0.2 - адрес этого же сервера, который еще и является шлюзом.
8. sudo
Сразу расставим все точки. Дабы не было путаницы. Политика безопасности в freebsd определяется группами, т.е. если пользователь принадлежит группе wheel, то пользователь может выполнить команду su, в остальных случаях sorry. В linux (в частности ubuntu/debian) sudo используется для разграничения пользователей, которые могут выполнять ту самую команду su. Мы будем использовать sudo для того, чтобы выполнять действия, на которые нужны привилегия su, а именно приложение pfctl на право добавления/удаления записи в таблицу. Вот, собственно, конфиг sudoers:
Cmnd_Alias WIFI = /sbin/pfctl , /bin/sh%www ALL = NOPASSWD : WIFI
Эти 2 строки добавляются в самый конец файла. Поясню, что создается алиас WIFI для списка программ pfctl и sh. Далее разрешаем использовать команды, прописанные в WIFI для группы www. Именно для группы. Почему для www? потому что скрипт valid.php выполняется от пользователя www.
9. mrtg
Чтобы хоть как-то мониторить количество открытых сессий на сервере можно набросать скрипт для mrtg, который будет отрисовывать график с подключениями.
in=`/sbin/pfctl -t permgroup -T show | /usr/bin/wc -l`
out=`/sbin/pfctl -t permgroup -T show | /usr/bin/wc -l`
/bin/echo $in
/bin/echo $out
/bin/echo `/usr/bin/uptime | /usr/bin/cut -d, -f1`
/bin/echo authuser
В заключении рассмотрим настройку самого pflog.
pflog_logfile="/var/log/pflog"
Настраивается он добавлением этих 2х строк в /etc/rc.conf:
pflog_enable="YES"pflog_logfile="/var/log/pflog"