Привет Хабр! Не так давно, в нашей организации встала задача узаконить wifi доступ, но чтобы в дальнейшем использование системы было бесплатно. (Согласно постановлению Правительства №758 от 31 июля 2014г. и №801 от 12 августа 2014 г. — все публичные WIFI сети обязаны производить идентификацию пользователей). У нас 10 залов для мероприятий (от 30 до 400 человек), а в день в среднем проходит от 4 до 12, плюс постоянная текучка народа и капризные пользователи.

Для начала расскажу, как у нас организована сеть. Если не вдаваться в подробности, то развешены точки доступа HP MSM430(J9651), управление через HP MSM760(J9420A) и шлюз HP F1000-EI (JG214A). Выбор оборудования не удачен, но работаем с тем, что имеем.
Так сложилось, что по жизни я больше полюбил Windows системы, но получив задачу, начитавшись кучу статей, пришел к выводу, что для этой цели лучше всего подойдет *nix система. Выбор пал на Ubuntu сервер 16.04. Дальше было несколько дней мучений, но в итоге все получилось.
Эта статья для тех, кто любит Windows, смотрит на Ubuntu и ставит с нуля кучу софта.
Как я решил все организовать:
Имеется открытая сеть, назовем ее Free. Пользователь при подключении переадресуется на хотспот со страницей авторизации. Там ему выдается код доступа к интернету и номер телефона, на которое он должен отправить сообщение (немного необычно, но стояла задача экономии, в том числе и на смс). Как только сообщение приходит к нам, доступ в интернет сразу открывается. Оговорюсь, симку и номер в модеме лучше использовать МТС (не реклама), так как только у них не нашел возможности отправить СМС с сайта без указания левого номера (хотя это проблема, но в процессе решения).
Что нам потребуется:
Начнем.
Здесь все довольно банально:
Смотрим, какие у нас присутствуют сетевые карты и какие назначены им логические имена:
В моем случае, это eth0 и eth1:
Редактируем файл настройки сетевых интерфейсов:
Убедимся в том, что в системе действительно присутствуют IPv6 интерфейсы:
Также можно увидеть, что некоторые приложения вывешивают TCP прослушиватели на интерфейсах IPv6. Посмотреть все прослушиваемые в системе порты можно командой:
Чтобы выключить поддержку IPv6 на всех сетевых интерфейсах сразу, открываем на редактирование файл sysctl.conf
В конец файла добавляем строки для включения форвардинга и отключения IPv6:
Для проверки того, что наша опция сможет быть прочитана sysctl во время загрузки выполним:
В качестве сервера баз данных, выбрал MaridDB. По функционалу в чем-то даже лучше MySQL, но статья не об этом.
Проверяем, все ли хорошо у нас запустилось:
Есть много статей, как собирать и устанавливать прокси, но этот этап оказался наверное самый муторный. По умолчанию, в репозитарии убунты лежит Squid без поддержки SSL. Решил пересобрать, и так прошло 2 дня… В итоге получился свой мануал, как собрать под x64 последнюю версию 3.5.20.
Ставим необходимый софт для сборки:
Расcкомментируем репозитарии исходников и добавим новый:
Новый репозитарий, будет ругаться на ключи, поэтому сразу их получим:
Не забываем обновить информацию о репозитариях:
Чтобы не захламить рабочую папку, переходим в tmp и скачиваем из testing последнюю версию squid с правилами для сборки под debian
Текущая версия 3.5.19, обновляемся до последней 3.5.21
Добавляем строчки (не забываем указать путь к openssl.cnf, у меня это /etc/ssl)
Исправляем ошибку (постоянные сообщения в логах: SECURITY ALERT: Host header forgery detected on local=...:443 remote=...:* ), хорошо описанную в статье, с оценкой всех рисков безопасности. (В статье описано о версии 3.5.12, здесь немного изменился код).
Ищем функцию hostHeaderIpVerify и немного изменяем ее код:
Подтверждаем патч и собираем (ждем примерно 10-15 минут)
Смотрим, какие пакеты у нас собрались:
Если пакетов нет, значит проверить папку
И начинаем установку Squid:
если по каким-либо причинам, подвис установщик, то сбрасываем блокировку:
запускаем и проверяем статус
в ответ должны увидеть что-то похожее
Проверяем установленную версию Squid
Теперь займемся его настройкой, для начала создадим SSL сертификат и сохраним конфиг по умолчанию:
Файл конфигурации, почти без изменений взят из статьи.
Создаем файл со списком блокируемых ресурсов
Обращаю внимание, что логи будем писать в базу данных. Для этого создаем таблицу:
запускаем и проверяем статус
в ответ должны увидеть что-то похожее
Проверяем используемые порты и версию установленного squid
Так как, используется кластер под HyperV 2012R2, то возникает проблема, а именно как нам воткнуть модем. В нашей организации довольно успешно используется: USB-Redirector. Ставим его под Ubuntu
подключаемся к серверу, куда подключили модем
смотрим перечень всех usb устройств
устанавливаем драйверы модема
подключаемся и проверяем, установлен ли модем
в ответ должны увидеть:
USB устройство требуется перевести в режим модема, для этого ставим программу minicon:
Запускаем ее настройку:
Выбираем «Настройка последовательного порта» и в пункт «последовательный порт» ставим /dev/ttyUSB0
Больше ничего не меняем в настройках. Для переключения режимов работы в модемах huawei используются следующие at-команды:
AT^U2DIAG=0 -устройство в режиме только модем
AT^U2DIAG=1 -устройство в режиме модем + CD-ROM
AT^U2DIAG=255 -устройство в режиме модем + CD-ROM + Card Reader
AT^U2DIAG=256 -устройство в режиме модем + Card Reader
Включаем режим «только модем»:
AT^U2DIAG=0
В ответ получаем «ОК». Выходим из программы, для этого жмем Ctrl+A и Q.
Информацию о пакеты можно найти на сайте разработчика.
Устанавливаем и настраиваем:
находим строчку [GSM1]
создаем файл обработчика входящих смс и делаем его исполняемым
Так как php обновилось до 7 версии и во всех репозитариях ubuntu уже лежит php7, то добавляем новый и ставим:
останавливаем установленный сервис и редактируем файлы настройки
Можно убедится в том, что права доступа к сокету установлены верно:
Проверяем:
Переходим к Nginx
Основные настройки Nginx хранятся в файле /etc/nginx/nginx.conf.
Настройки базового сайта хранятся в файле /etc/nginx/sites-available/default.
Базовый конфигурационный файл сайта принято помещать в папку /etc/nginx/sites-available/ и затем включить его путём добавления символической ссылки на этот файл в папке /etc/nginx/sites-enabled/.
Дальше буду краток, так как пояснения можно почитать по ссылке. Создаем общие файлы настройки сервера, в которых описываем настройки безопасности, сжатия, кэширования и php.
В моем случаи, у меня был публичный wildcard сертификат для моего домена. Распаковываю файл сертификата и устанавливаю права доступа
Настраиваем наш сервер:
и делаем редирект с сервера по умолчанию (не забываем, что DNS сервер должен резолвить имя hotspot.domain.com):
Для более удобной работы с базой данных, устанавливаем phpmyadmin.
и аналогично подключаем к nginx
перезапускаемся
В данном разделе, нам требуется ограничить доступ к серверу и завернуть трафик на прокси. Для начала, настроим сохранение всех правил после перезагрузки:
так как в нашей задаче, нам необходимо, чтобы сохранялись и таблицы ipset, то немного правим следующий файл:
Для сохранения правил на фаерволе используем команду:
Для отслеживания и сброса установленных соединений используем conntrack
Настраиваем правила iptables
Для отлавливания проблем используем следующие команды
Создаем таблицы в нашей базе данных:
создаем скрипт, при входе в систему, для проверки работы всех служб:
устанавливаем права запуска и добавляем на старт
а теперь исходники php файлов:
Ну а теперь, добавим в sudoers права для управления iptables из php
На этом вроде всё. Система в работе уже месяц, полёт нормальный. Спасибо за внимание!

Для начала расскажу, как у нас организована сеть. Если не вдаваться в подробности, то развешены точки доступа HP MSM430(J9651), управление через HP MSM760(J9420A) и шлюз HP F1000-EI (JG214A). Выбор оборудования не удачен, но работаем с тем, что имеем.
Так сложилось, что по жизни я больше полюбил Windows системы, но получив задачу, начитавшись кучу статей, пришел к выводу, что для этой цели лучше всего подойдет *nix система. Выбор пал на Ubuntu сервер 16.04. Дальше было несколько дней мучений, но в итоге все получилось.
Эта статья для тех, кто любит Windows, смотрит на Ubuntu и ставит с нуля кучу софта.
Как я решил все организовать:
Имеется открытая сеть, назовем ее Free. Пользователь при подключении переадресуется на хотспот со страницей авторизации. Там ему выдается код доступа к интернету и номер телефона, на которое он должен отправить сообщение (немного необычно, но стояла задача экономии, в том числе и на смс). Как только сообщение приходит к нам, доступ в интернет сразу открывается. Оговорюсь, симку и номер в модеме лучше использовать МТС (не реклама), так как только у них не нашел возможности отправить СМС с сайта без указания левого номера (хотя это проблема, но в процессе решения).
Что нам потребуется:
- лошадка Ubuntu Server 16.04
- прокси Squid в прозрачном режиме
- Mysql (MariaDB)
- Nginx
- PHP FPM
- USB redirector (виртуальная машинка под HyperV)
- модем Huawei E153 МТС
- SMS tools для чтения смс
- и тд. и тп.
Начнем.
Установка Ubuntu Server 16.04
Здесь все довольно банально:
- Создаем виртуальную машинку (2 ядра, 4 Гб памяти, 2 сетевых интерфейса, 30 Гб диск)
- Качаем последний дистрибутив, подключаем, ставим...
- Настраиваем сетевые интерфейсы, один смотрит в vlan сети wifi, второй в сторону шлюза
Настройка сети и форвардинг пакетов
Смотрим, какие у нас присутствуют сетевые карты и какие назначены им логические имена:
cat /proc/net/dev
В моем случае, это eth0 и eth1:
Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo: 632643353 3624368 0 0 0 0 0 0 632643353 3624368 0 0 0 0 0 0 eth1: 8789521059 30492824 0 0 0 0 0 0 65843784529 28992970 0 0 0 0 0 0 eth0: 65798728800 56063700 0 0 0 0 0 0 8382628950 29920038 0 0 0 0 0 0
Редактируем файл настройки сетевых интерфейсов:
nano /etc/network/interfaces
auto eth0 iface eth0 inet static # в сторону интернет шлюза address 10.66.66.6 netmask 255.255.255.240 network 10.66.66.0 broadcast 10.66.66.15 gateway 10.66.66.1 dns-nameservers 10.66.66.1 auto eth1 iface eth1 inet static # в сторону wifi пользователей address 10.0.87.254 netmask 255.255.248.0 network 10.0.80.0 broadcast 10.0.87.255
Убедимся в том, что в системе действительно присутствуют IPv6 интерфейсы:
ip a | grep inet
Также можно увидеть, что некоторые приложения вывешивают TCP прослушиватели на интерфейсах IPv6. Посмотреть все прослушиваемые в системе порты можно командой:
sudo ss -lnptu | sort
Чтобы выключить поддержку IPv6 на всех сетевых интерфейсах сразу, открываем на редактирование файл sysctl.conf
sudo nano -Y sh /etc/sysctl.conf
В конец файла добавляем строки для включения форвардинга и отключения IPv6:
net.ipv4.ip_forward=1 net.ipv6.conf.all.disable_ipv6 = 1
Для проверки того, что наша опция сможет быть прочитана sysctl во время загрузки выполним:
sudo sysctl -p
/etc/init.d/networking restart
Установка MySQL
В качестве сервера баз данных, выбрал MaridDB. По функционалу в чем-то даже лучше MySQL, но статья не об этом.
apt-get install mariadb-server #настраиваем пароли на доступ mysql_secure_installation #запускаем mysql и сбрасываем привилегии mysql -u root use mysql; update user set plugin='' where User='root'; flush privileges;
Проверяем, все ли хорошо у нас запустилось:
service mysql status
Установка Squid с поддержкой SSL и отключением IPv6
Есть много статей, как собирать и устанавливать прокси, но этот этап оказался наверное самый муторный. По умолчанию, в репозитарии убунты лежит Squid без поддержки SSL. Решил пересобрать, и так прошло 2 дня… В итоге получился свой мануал, как собрать под x64 последнюю версию 3.5.20.
Ставим необходимый софт для сборки:
apt-get install git fakeroot checkinstall build-essential devscripts patch libssl-dev libgnutls28-dev apt-cache policy squid3 apt-get update apt-get build-dep squid3
Расcкомментируем репозитарии исходников и добавим новый:
nano /etc/apt/sources.list deb-src http://ftp.de.debian.org/debian/ testing main contrib non-free
Новый репозитарий, будет ругаться на ключи, поэтому сразу их получим:
gpg --keyserver keyserver.ubuntu.com --recv 8B48AD6246925553 gpg --export --armor 8B48AD6246925553 | sudo apt-key add - gpg --keyserver keyserver.ubuntu.com --recv 7638D0442B90D010 gpg --export --armor 7638D0442B90D010 | sudo apt-key add -
Не забываем обновить информацию о репозитариях:
apt-get update
Чтобы не захламить рабочую папку, переходим в tmp и скачиваем из testing последнюю версию squid с правилами для сборки под debian
cd /tmp/ apt-get source squid3
Текущая версия 3.5.19, обновляемся до последней 3.5.21
wget http://www.squid-cache.org/Versions/v3/3.5/squid-3.5.21.tar.gz tar -xf squid-3.5.21.tar.gz mkdir ./squid-3.5.21/debian/ cp -r ./squid3-3.5.19/debian/* ./squid-3.5.21/debian/ cd squid-3.5.21/ nano debian/rules
Добавляем строчки (не забываем указать путь к openssl.cnf, у меня это /etc/ssl)
--disable-ipv6 \ --enable-icap-client \ --enable-ssl-crtd \ --with-openssl=/etc/ssl \
Исправляем ошибку (постоянные сообщения в логах: SECURITY ALERT: Host header forgery detected on local=...:443 remote=...:* ), хорошо описанную в статье, с оценкой всех рисков безопасности. (В статье описано о версии 3.5.12, здесь немного изменился код).
nano ./src/client_side_request.cc
Ищем функцию hostHeaderIpVerify и немного изменяем ее код:
void ClientRequestContext::hostHeaderIpVerify(const ipcache_addrs* ia, const DnsLookupDetails &dns) { Comm::ConnectionPointer clientConn = http->getConn()->clientConnection; // note the DNS details for the transaction stats. http->request->recordLookup(dns); if (ia != NULL && ia->count > 0) { // Is the NAT destination IP in DNS? for (int i = 0; i < ia->count; ++i) { if (clientConn->local.matchIPAddr(ia->in_addrs[i]) == 0) { debugs(85, 3, HERE << "validate IP " << clientConn->local << " possible from Host:"); http->request->flags.hostVerified = true; http->doCallouts(); return; } debugs(85, 3, HERE << "validate IP " << clientConn->local << " non-match from Host: IP " << ia->in_addrs[i]); } } // patch for SECURITY ALERT: Host header forgery detected http->request->flags.hostVerified = true; http->doCallouts(); return; debugs(85, 3, HERE << "FAIL: validate IP " << clientConn->local << " possible from Host:"); hostHeaderVerifyFailed("local IP", "any domain IP"); }
Подтверждаем патч и собираем (ждем примерно 10-15 минут)
dpkg-source --commit #patch update to squid 3.5.20 debuild
Смотрим, какие пакеты у нас собрались:
ls -l /tmp/ | grep .deb$
Если пакетов нет, значит проверить папку
ls -l /tmp/squid3-3.5.19/ | grep .deb$
И начинаем установку Squid:
apt-get install squid-langpack libdbi-perl dpkg -i squid-common_3.5.19-1_all.deb dpkg -i squid_3.5.19-1_amd64.deb dpkg -i squid3_3.5.19-1_all.deb dpkg -i squidclient_3.5.19-1_amd64.deb
если по каким-либо причинам, подвис установщик, то сбрасываем блокировку:
fuser -vki /var/lib/dpkg/lock
запускаем и проверяем статус
service squid start systemctl status -l squid
в ответ должны увидеть что-то похожее
squid.service - LSB: Squid HTTP Proxy version 3.x Loaded: loaded (/etc/init.d/squid; bad; vendor preset: enabled) Active: active (running)
Проверяем установленную версию Squid
/usr/sbin/squid -v Squid Cache: Version 3.5.21 Service Name: squid Ubuntu linux
Теперь займемся его настройкой, для начала создадим SSL сертификат и сохраним конфиг по умолчанию:
cd /etc/squid openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem mv ./squid.conf ./squid.conf.default nano ./squid.conf
Файл конфигурации, почти без изменений взят из статьи.
acl localnet src 10.0.80.0/21 acl SSL_ports port 443 acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 # https acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 1025-65535 # unregistered ports acl Safe_ports port 280 # http-mgmt acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http acl CONNECT method CONNECT dns_nameservers 10.66.66.1 http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow localhost manager http_access deny manager http_access allow localnet http_access allow localhost http_access deny all #http_port 3128 #прозрачный порт указывается опцией intercept http_port 10.0.87.254:3128 intercept options=NO_SSLv3:NO_SSLv2 #также нужно указать непрозрачный порт, ибо если захотите вручную указать адрес #прокси в браузере, указав прозрачный порт, вы получите ошибку доступа, поэтому нужно #указывать непрозрачный порт в браузере, если конечно такое желание будет, к тому же в логах #сыпятся ошибки о том, что непрохрачный порт не указан=) http_port 10.0.87.254:3130 options=NO_SSLv3:NO_SSLv2 #и наконец, указываем HTTPS порт с нужными опциями https_port 10.0.87.254:3129 intercept ssl-bump options=ALL:NO_SSLv3:NO_SSLv2 connection-auth=off cert=/etc/squid/squidCA.pem always_direct allow all sslproxy_cert_error allow all sslproxy_flags DONT_VERIFY_PEER #укажем правило со списком блокируемых ресурсов (в файле домены вида .domain.com) acl blocked ssl::server_name "/etc/squid/blocked_https.txt" acl step1 at_step SslBump1 ssl_bump peek step1 #терминируем соединение, если клиент заходит на запрещенный ресурс ssl_bump terminate blocked ssl_bump splice all sslcrtd_program /usr/lib/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB coredump_dir /var/spool/squid refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 refresh_pattern . 0 20% 4320 cache_dir aufs /var/spool/squid 2048 49 256 maximum_object_size 61440 KB minimum_object_size 3 KB cache_swap_low 90 cache_swap_high 95 maximum_object_size_in_memory 512 KB memory_replacement_policy lru #logfile_rotate 31 logfile_daemon /usr/lib/squid/log_db_daemon access_log daemon:/127.0.0.1:3306/base/table/user/password squid
Создаем файл со списком блокируемых ресурсов
nano ./blocked_https.txt
Обращаю внимание, что логи будем писать в базу данных. Для этого создаем таблицу:
CREATE TABLE `access_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time_since_epoch` decimal(15,3) DEFAULT NULL, `time_response` int(11) DEFAULT NULL, `ip_client` char(15) DEFAULT NULL, `ip_server` char(15) DEFAULT NULL, `http_status_code` varchar(10) DEFAULT NULL, `http_reply_size` int(11) DEFAULT NULL, `http_method` varchar(20) DEFAULT NULL, `http_url` varchar(500) DEFAULT NULL, `http_username` varchar(20) DEFAULT NULL, `http_mime_type` varchar(50) DEFAULT NULL, `squid_request_status` varchar(50) DEFAULT NULL, `squid_hier_status` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
запускаем и проверяем статус
service squid start systemctl status -l squid
в ответ должны увидеть что-то похожее
squid.service - LSB: Squid HTTP Proxy version 3.x Loaded: loaded (/etc/init.d/squid; bad; vendor preset: enabled) Active: active (running)
Проверяем используемые порты и версию установленного squid
sudo ss -lnptu | grep :3128 sudo ss -lnptu | grep :3129 sudo ss -lnptu | grep :3130 squid -version Squid Cache: Version 3.5.20
Ставим USB-Redirector и модем
Так как, используется кластер под HyperV 2012R2, то возникает проблема, а именно как нам воткнуть модем. В нашей организации довольно успешно используется: USB-Redirector. Ставим его под Ubuntu
cd /tmp/ wget http://www.incentivespro.com/usb-redirector-linux-x86_64.tar.gz tar -xf usb-redirector-linux-x86_64.tar.gz ./usb-redirector-linux-x86_64/installer.sh install-client
подключаемся к серверу, куда подключили модем
usbclnt -addserver 10.X.X.X:32032 usbclnt -autoconnect on 1
смотрим перечень всех usb устройств
usbclnt -l ================= USB CLIENT OPERATION SUCCESSFUL =============== List of USB servers and devices: 1: USB server at 10.X.X.X:32032 Mode: auto-connect Status: connected - 7: HUAWEI Mobile Vid: 12d1 Pid: 1001 Port: 3-2 Mode: manual-connect Status: disconnected
устанавливаем драйверы модема
apt-get install usb-modeswitch usb-modeswitch-data
подключаемся и проверяем, установлен ли модем
usbclnt -connect 1-7 ls /dev | grep ttyUSB
в ответ должны увидеть:
ttyUSB0 ttyUSB1 ttyUSB2
USB устройство требуется перевести в режим модема, для этого ставим программу minicon:
apt-get install minicom
Запускаем ее настройку:
minicom -s
Выбираем «Настройка последовательного порта» и в пункт «последовательный порт» ставим /dev/ttyUSB0
Больше ничего не меняем в настройках. Для переключения режимов работы в модемах huawei используются следующие at-команды:
AT^U2DIAG=0 -устройство в режиме только модем
AT^U2DIAG=1 -устройство в режиме модем + CD-ROM
AT^U2DIAG=255 -устройство в режиме модем + CD-ROM + Card Reader
AT^U2DIAG=256 -устройство в режиме модем + Card Reader
Включаем режим «только модем»:
AT^U2DIAG=0
В ответ получаем «ОК». Выходим из программы, для этого жмем Ctrl+A и Q.
Устанавливаем SMS-tools
Информацию о пакеты можно найти на сайте разработчика.
Устанавливаем и настраиваем:
apt-get install smstools nano /etc/smsd.conf
находим строчку [GSM1]
[GSM1] device = /dev/ttyUSB0 incoming = yes baudrate = 9600 eventhandler = /var/www/sms_recieve.php
создаем файл обработчика входящих смс и делаем его исполняемым
nano /var/www/sms_recieve.php chmod 755 /var/www/sms_recieve.php service smstools restart
Настраиваем DHCP сервер
apt-get install isc-dhcp-server nano /etc/default/isc-dhcp-server #указываем, на каком интерфейсе будет слушать dhcp сервер INTERFACES="eth1" sudo nano /etc/dhcp/dhcpd.conf # указываем authoritative; subnet 10.0.80.0 netmask 255.255.248.0 { range 10.0.80.1 10.0.86.254; option domain-name-servers 10.0.87.254; option domain-name "wifi-free"; option subnet-mask 255.255.248.0; option routers 10.0.87.254; option broadcast-address 10.0.87.255; default-lease-time 7200; #2h max-lease-time 72000; #20h } /etc/init.d/isc-dhcp-server restart
Настраиваем Nginx и PHP 5.6 FPM
Так как php обновилось до 7 версии и во всех репозитариях ubuntu уже лежит php7, то добавляем новый и ставим:
add-apt-repository ppa:ondrej/php apt-get install php5.6-cli php5.6-common php5.6-mysql php5.6-gd php5.6-fpm php5.6-cgi php-pear
останавливаем установленный сервис и редактируем файлы настройки
service php5.6-fpm stop nano /etc/php/5.6/fpm/php.ini cgi.fix_pathinfo = 0 post_max_size = 200M upload_max_filesize = 200M nano /etc/php/5.6/fpm/pool.d/www.conf security.limit_extensions = .php .php3 .php4 .php5 listen = /run/php/php5.6-fpm.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 service php5.6-fpm start
Можно убедится в том, что права доступа к сокету установлены верно:
ls -la /run/php/php5.6-fpm.sock #srw-rw---- 1 www-data www-data 0 May 2 16:36 /run/php/php5.6-fpm.sock
Проверяем:
php -v PHP 5.6.23-2+deb.sury.org~xenial+1 (cli) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
Переходим к Nginx
apt-get install nginx nginx-extras
Основные настройки Nginx хранятся в файле /etc/nginx/nginx.conf.
Настройки базового сайта хранятся в файле /etc/nginx/sites-available/default.
Базовый конфигурационный файл сайта принято помещать в папку /etc/nginx/sites-available/ и затем включить его путём добавления символической ссылки на этот файл в папке /etc/nginx/sites-enabled/.
touch /etc/nginx/sites-available/hotspot.domain.com ln -s /etc/nginx/sites-available/hotspot.domain.com /etc/nginx/sites-enabled/ mkdir /etc/nginx/common
Дальше буду краток, так как пояснения можно почитать по ссылке. Создаем общие файлы настройки сервера, в которых описываем настройки безопасности, сжатия, кэширования и php.
touch /etc/nginx/common/upstream nano /etc/nginx/common/upstream upstream php-fpm { # PHP5.6-FPM сервер server unix:/run/php/php5.6-fpm.sock; }
touch /etc/nginx/common/security nano /etc/nginx/common/security add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff";
touch /etc/nginx/common/gzip nano /etc/nginx/common/gzip gzip on; gzip_disable "msie6"; gzip_comp_level 6; gzip_min_length 1100; gzip_buffers 16 8k; gzip_proxied any; gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/javascript application/json application/xml+rss;
touch /etc/nginx/common/php-fpm nano /etc/nginx/common/php-fpm # Настройки порта или сокета PHP-FPM производятся в файле "/etc/php/5.6/fpm/pool.d/www.conf" fastcgi_pass php-fpm; # Порядок важен - строчка "include fastcgi_params" должна быть первой include fastcgi_params; fastcgi_split_path_info ^(.+?\.php)(/.*)?$; # Вместо переменной "$document_root" можно указать адрес к корневому каталогу сервера и это желательно (см. http://wiki.nginx.org/Pitfalls) fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name; # См. http://trac.nginx.org/nginx/ticket/321 set $path_info $fastcgi_path_info; fastcgi_param PATH_INFO $path_info; # Additional variables fastcgi_param SERVER_ADMIN email@example.com; fastcgi_param SERVER_SIGNATURE nginx/$nginx_version; fastcgi_index index.php;
touch /etc/nginx/common/cache nano /etc/nginx/common/cache location ~* ".+\.(?:ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|css|swf|js|atom|jpe?g|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$" { access_log off; log_not_found off; expires max; }
В моем случаи, у меня был публичный wildcard сертификат для моего домена. Распаковываю файл сертификата и устанавливаю права доступа
openssl pkcs12 -in certname.pfx -nocerts -out /etc/nginx/ssl/key.pem -nodes openssl pkcs12 -in certname.pfx -nokeys -out /etc/nginx/ssl/cert.pem openssl rsa -in /etc/nginx/ssl/key.pem -out /etc/nginx/ssl/domain.key cd /etc/nginx/ssl/ chown www-data:www-data domain.key chmod 400 domain.key
touch /etc/nginx/common/ssl nano /etc/nginx/common/ssl ssl_certificate /etc/nginx/ssl/domain.crt; ssl_certificate_key /etc/nginx/ssl/domain.key; ssl_session_timeout 20m; # время 20 минут ssl_session_cache shared:SSL:20m; # размер кеша 20МБ ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AE$
Настраиваем наш сервер:
nano /etc/nginx/sites-available/hotspot.domain.com include common/upstream; server { listen 80; server_name hotspot.domain.com; root /var/www; index index.php index.html index.htm; client_max_body_size 200m; # увеличение максимального объема файла для загрузки до 200МБ # Buffers fastcgi_buffers 64 4K; include common/security; include common/gzip; location "/" { index index.php index.html index.htm; # варианты индексных файлов если имя файла в запросе не задано try_files $uri $uri/ =404; # проверить есть ли файл из запроса на диске, иначе - вернуть ошибку 404 include common/deny; include common/cache; include common/php-fpm; } }
и делаем редирект с сервера по умолчанию (не забываем, что DNS сервер должен резолвить имя hotspot.domain.com):
nano /etc/nginx/sites-available/default server { listen 80 default_server; #listen [::]:80 default_server; listen 443 ssl default_server; #listen [::]:443 ssl default_server; include common/ssl; rewrite ^ http://hotspot.domain.com?url=$scheme://$host$request_uri? redirect; ... }
Настраиваем phpmyadmin
Для более удобной работы с базой данных, устанавливаем phpmyadmin.
apt-get install phpmyadmin apt-get install mcrypt php5.6-mcrypt php5.6-mbstring php-gettext
touch /etc/nginx/common/phpmyadmin nano /etc/nginx/common/phpmyadmin location /phpmyadmin { root /usr/share/; index index.htm index.html index.php; location ~ ^/phpmyadmin/(.+.php)$ { try_files $uri = 404; root /usr/share/; fastcgi_pass unix:/run/php/php5.6-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $request_filename; include /etc/nginx/fastcgi_params; } location ~* ^/phpmyadmin/(.+.(html|ico|xml|css|jpg|png|js|txt|gif|jpeg))$ { root /usr/share/; } } location /phpMyAdmin { rewrite ^/* /phpmyadmin last; }
и аналогично подключаем к nginx
nano /etc/nginx/sites-available/hotspot.domain.com include common/phpmyadmin;
перезапускаемся
service nginx restart service php5.6-fpm restart
Настройка фаервола iptables
В данном разделе, нам требуется ограничить доступ к серверу и завернуть трафик на прокси. Для начала, настроим сохранение всех правил после перезагрузки:
apt-get install iptables-persistent ipset
так как в нашей задаче, нам необходимо, чтобы сохранялись и таблицы ipset, то немного правим следующий файл:
nano /usr/share/netfilter-persistent/plugins.d/15-ip4tables #в функцию save_rules() touch /etc/iptables/rules.v4 touch /etc/iptables/ipset.rules chmod 0642 /etc/iptables/ipset.rules chmod 0640 /etc/iptables/rules.v4 iptables-save > /etc/iptables/rules.v4 ipset save > /etc/iptables/ipset.rules #в функцию load_rules() ipset restore < /etc/iptables/ipset.rules iptables-restore < /etc/iptables/rules.v4 2> /dev/null
Для сохранения правил на фаерволе используем команду:
netfilter-persistent save
Для отслеживания и сброса установленных соединений используем conntrack
apt-get install conntrack
Настраиваем правила iptables
#создаем таблицу авторизованных mac-ip ipset --create authorized macipmap --network 10.0.80.0/21 ipset -L authorized #создаем дополнительные цепочки обработки правил iptables -t nat -N toSQUID iptables -t nat -N toHOTSPOT #очищаем все ранее созданные правила iptables -t nat -F PREROUTING #пробрасываем DNS на наш сервер iptables -t nat -A PREROUTING -i eth1 -p udp --dport 53 -j DNAT --to 10.66.66.1 #если ip,mac авторизован, то перенаправляем на squid iptables -t nat -A PREROUTING -i eth1 -m set --match-set authorized src,src -j toSQUID #если ip,mac не авторизован, то перенаправляем на заглушку iptables -t nat -A PREROUTING -i eth1 -j toHOTSPOT iptables -t nat -F toHOTSPOT # в заглушке, все запросы перенаправляем на наш сервер nginx iptables -t nat -A toHOTSPOT -p tcp -m multiport --dports 80,8080 -j DNAT --to-destination 10.0.87.254:80 iptables -t nat -A toHOTSPOT -p tcp -m multiport --dports 443 -j DNAT --to-destination 10.0.87.254:443 iptables -t nat -A toHOTSPOT -j RETURN iptables -t nat -F toSQUID # перенаправляем разрешенные порты на прокси #создаем обход хотспота для telegram (так и не смог заставить работать через squid) iptables -t nat -A toSQUID -p tcp -d 149.154.164.0/22 --dport 443 -j ACCEPT #аналогично для whatsapp iptables -t nat -A toSQUID -p tcp -m multiport --dport 4244,5242,5228,5223,5222 -j ACCEPT iptables -t nat -A toSQUID -p tcp -m multiport --dports 80,25,465,110,995,119,563,8080 -j REDIRECT --to-ports 3128 iptables -t nat -A toSQUID -p tcp -m multiport --dports 443 -j REDIRECT --to-ports 3129 iptables -t nat -A toSQUID -j RETURN #Включаем NAT для прошедших пакетов iptables -t nat -A POSTROUTING -s 10.0.80.0/21 -o eth0 -j MASQUERADE #политика по умолчанию для входящих пакетов iptables -P INPUT ACCEPT iptables -F INPUT #разрешаем траффик на lo iptables -A INPUT -i lo -j ACCEPT #разрешаем доступ к портам управления из вышестоящей сети iptables -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -j ACCEPT #разрешаем пинг и трасерт iptables -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT #разрешаем работу уже открытых соединений iptables -A INPUT -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p UDP -m state --state ESTABLISHED,RELATED -j ACCEPT #разрешаем доступ на прокси iptables -A INPUT -i eth1 -p tcp -m multiport --dport 3128,3129,3130 -j ACCEPT iptables -A INPUT -i eth1 -p udp -m multiport --dport 3128,3129,3130 -j ACCEPT №разрешаем доступ на заглушку iptables -A INPUT -i eth1 -p tcp -m multiport --dports 80,443 -j ACCEPT #политика по умолчанию для входящих пакетов iptables -P INPUT DROP #создаем цепочку для проблемных сервисов, которым разрешена пересылка iptables -N FORWARD_AUTHORIZED iptables -F FORWARD_AUTHORIZED # разрешаем пересылку telegram iptables -A FORWARD_AUTHORIZED -p tcp -d 149.154.164.0/22 --dport 443 -j ACCEPT # разрешаем пересылку whatsapp iptables -A FORWARD_AUTHORIZED -p tcp -m multiport --dport 4244,5242,5228,5223,5222 -j ACCEPT iptables -A FORWARD_AUTHORIZED -j RETURN #политика по умолчанию для пересылаемых пакетов iptables -P FORWARD ACCEPT iptables -F FORWARD #разрешаем пересылку на dns iptables -A FORWARD -i eth1 -p udp --dport 53 -d 10.66.66.1 -j ACCEPT #разрешаем работу уже открытых соединений iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT #перенаправляем авторизованных клиентов на проверку в цепочку FORWARD_AUTHORIZED iptables -A FORWARD -i eth1 -m set --match-set authorized src,src -j FORWARD_AUTHORIZED #политика по умолчанию для пересылаемых пакетов iptables -P FORWARD DROP
Для отлавливания проблем используем следующие команды
#сброс установленных соединений с заданного ip conntrack -D conntrack --orig-src 10.0.8X.XXX #просмотр новых записей в логе tail -f /var/log/firewall | grep 10.0.8X.XXX
Настраиваем php файлы обработки запросов и скрипты
Создаем таблицы в нашей базе данных:
SET FOREIGN_KEY_CHECKS=0; CREATE TABLE IF NOT EXISTS `mac-auth` ( `mac` char(17) NOT NULL COMMENT 'мак адрес устройства', `code` int(6) NOT NULL COMMENT 'код авторизации', `phone` varchar(15) NOT NULL DEFAULT '' COMMENT 'телефонный номер с которого пришло смс', `updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'дата последнего изменения', `created` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'дата создания', UNIQUE KEY `mac` (`mac`), KEY `code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `mac-ip` ( `mac` char(17) NOT NULL COMMENT 'мак адрес устройства', `ip` varchar(15) NOT NULL COMMENT 'ip адрес устройства', `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'дата изменения', KEY `mac` (`mac`), KEY `ip` (`ip`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `mac-phone` ( `mac` char(17) NOT NULL COMMENT 'мак адрес устройства', `phone` varchar(15) NOT NULL COMMENT 'номер телефона', `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'дата изменения', KEY `mac` (`mac`), KEY `ip` (`phone`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `mac-ip` ADD CONSTRAINT `mac` FOREIGN KEY (`mac`) REFERENCES `mac-auth` (`mac`) ON DELETE CASCADE ON UPDATE CASCADE; SET FOREIGN_KEY_CHECKS=1;
создаем скрипт, при входе в систему, для проверки работы всех служб:
nano /var/www/check_services.sh #!/bin/bash function check { printf %-30s "check $1" if (( $(ps -ef | grep -v grep | grep $1 | wc -l) > 0 )) then echo -e "[\033[32;1m OK \033[0m]" else echo -e "[\033[31;1m ERROR \033[0m]" fi } check dhcpd check nginx check mysql check php-fpm check smstools check squid check usbsrvd
устанавливаем права запуска и добавляем на старт
chmod 755 /var/www/check_services.sh nano ~/.profile /var/www/check_services.sh
а теперь исходники php файлов:
nano /var/www/sms_recieve.php
#!/usr/bin/php <?php require_once 'hotspot/connect.php'; $sms_type = $argv[1]; $sms_file = $argv[2]; $sms_file_content = file_get_contents($sms_file); $i = strpos($sms_file_content, "\n\n"); $sms_headers_part = substr($sms_file_content, 0, $i); $sms_message_body = substr($sms_file_content, $i + 2); $sms_header_lines = split("\n", $sms_headers_part); $sms_headers = array(); foreach ($sms_header_lines as $header) { $i = strpos($header, ":"); if ($i !== false) $sms_headers[substr($header, 0, $i)] = substr($header, $i + 2); } $phone = (float)$sms_headers['From']; $code = (int)$sms_message_body; //проверяем базу на старые записи $interval = '30 DAY'; //$interval = '1 MINUTE'; $macs = sql_getRows('SELECT `mac` FROM `mac-auth` WHERE `code` = 1 AND `updated` < DATE_SUB(NOW(),INTERVAL '.$interval .')'); if (!empty($macs)){ $data = sql_getColumn('SELECT DISTINCT(`ip`) as `ip`,`mac` FROM `mac-ip` WHERE `mac` IN ("'.implode('","',$macs).'") ORDER BY `date` DESC','mac'); foreach ($data as $mac=>$ip){ sql_query('UPDATE `mac-auth` SET `code` = "0" WHERE `mac` IN ("'.implode('","',$macs).'")'); //удаляем авторизацию на фаерволе shell_exec('sudo ipset -D authorized '.$ip .','.$mac); //сбрасываем все подключения данного ip shell_exec('sudo conntrack -D conntrack --orig-src '.$ip); } shell_exec('sudo ipset save > /etc/iptables/ipset.rules'); } echo $phone.'-'.$code; $mac = sql_getValue('SELECT `mac` FROM `mac-auth` WHERE `code` = '.$code); if ($mac){ $ip = sql_getValue('SELECT DISTINCT(`ip`) FROM `mac-ip` WHERE `mac` = "'.$mac.'" ORDER BY `date` DESC'); echo '-'.$mac.'-'.$ip; //вносим в базу информацию о номере телефона sql_query('INSERT `mac-phone` (`mac`,`phone`) VALUES("'.$mac.'","'.$phone.'")'); sql_query('UPDATE `mac-auth` SET `phone` = "'.$phone.'", `code` = "1" WHERE `mac` = "'.$mac.'"'); //разрешаем доступ на фаерволе shell_exec('sudo ipset -A authorized '.$ip .','.$mac); shell_exec('sudo ipset save > /etc/iptables/ipset.rules'); shell_exec('sudo conntrack -D conntrack --orig-src '.$ip); } //удаляем сообщение unlink($sms_file); ?>
nano /var/www/hotspot/index.php
<?php //устанавливаем подключение с базой данных require_once 'connect.php'; //определяем ip адрес $ip = ''; if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } if (empty($ip)) $ip = $_SERVER['REMOTE_ADDR']; //проверяем правильность ip адреса if (!preg_match('/^10\.0\.8[0-7]\.\d{1,3}$/', $ip)) { $ip = false; } //определяем мак адрес if ($ip) $mac = trim(shell_exec("arp -a ".$ip." | awk '{print $4}'")); if (!isset($mac) || $mac == "entries") $mac = false; //определяем адрес по которому обращался пользователь $url = $_GET['url']; //if (strpos($url, 'gstatic.com')!==false) $url = 'http://www.domain.ru'; //выключаем кэширование браузером header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Дата в прошлом // строка ошибки $error = false; if (!$mac){ $error = 'Ошибка с Вашей сетевой картой. <br/>Доступ в интернет не может быть предоставлен.<br/><font class="eng error">Error with your network card. Internet access can not be granted</font>'; } else { //проверяем, не изменился ли ip адрес у абонента $base_ip = sql_getValue('SELECT DISTINCT(`ip`) FROM `mac-ip` WHERE `mac` = "'.$mac.'" ORDER BY `date` DESC'); if ($base_ip != $ip){ sql_query('INSERT INTO `mac-ip` (`mac`,`ip`) VALUES ("'.$mac.'","'.$ip.'")'); } //проверяем авторизацию мак адреса $code = sql_getValue('SELECT `code` FROM `mac-auth` WHERE `mac` = "'.$mac.'"'); switch ($code){ case '1': //абонент авторизован shell_exec('sudo ipset -A authorized '.$ip .','.$mac); shell_exec('sudo ipset save > /etc/iptables/ipset.rules'); //сбрасываем все подключения данного ip, иначе TOO_MANY_REDIRECTS shell_exec('sudo conntrack -D conntrack --orig-src '.$ip); header('Location: '.$url); die; break; case '': //новый абонент sql_query('INSERT INTO `mac-auth` (`mac`,`code`) VALUES ("'.$mac.'",0)'); case '0': //абонент без авторизации и без кода доступа //генерируем код do { $code = rand(10000,99999); } while(sql_getValue('SELECT `mac` FROM `mac-auth` WHERE `code` = "'.$code.'"')); sql_query('UPDATE `mac-auth` SET `code` = '.$code.' WHERE `mac` = "'.$mac.'"'); default: //абонент без авторизации, но с генерированным кодом break; } } ?> <!DOCTYPE HTML> <html> <head> <title>Хотспот</title> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <meta name="viewport" content="width=device-width, initial-scale=0.8, maximum-scale=1" /> </head> <body> <style type="text/css"> html, body { width: auto; margin: 0px; padding: 0px; } * { font-family: "Tahoma", sans-serif; font-size: 14px; text-align:center; font-style: normal; font-variant: normal; font-weight: normal; color: #000; } .center { width: 400px; padding: 10px; margin: auto; } .logo { background-image: url("/logo2.gif"); width: 177px; height: 209px; margin: auto; } .header { font-size: 16px; padding: 10px; } .repeat { padding: 10px; } .sms { font-size: 11px; color: #4c4b4b; padding: 10px; } .law { font-size: 11px; color: #4c4b4b; padding: 10px; } .code { font-size: 16px; font-weight: bold; } .num { font-size: 16px; font-weight: bold; } .internet-disabled { background-color: #dadbdb; color: white; padding: 7px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border: 2px solid #ffffff; border-radius: 4px; box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); } .internet { background-color: #3e315f; color: white; padding: 7px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border: 2px solid #ffffff; border-radius: 4px; box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); } .internet:hover { background-color: #ffffff; color: #3e315f; border: 2px solid #3e315f; box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19); } .eng { font-size: 12px; line-height: 12px; } .error { color: #d11313; } </style> <?php if (!$error) {?> <script type="text/javascript"> window.onload = function(){ window.htime = 60; check = function(){ if (window.htime <=0 ) { return true; } else { return false; } } window.htimer = window.setInterval(function(){ document.getElementById('button').innerHTML = 'осталось ' + window.htime + ' сек.'; window.htime -= 1; if (window.htime <= 0) { window.clearInterval(window.htimer); document.getElementById('button').className = "internet"; document.getElementById('button').innerHTML = 'перейти в интернет'; } }, 1000); } </script> <?php } ?> <div class="center"> <div class="logo"></div> <div class="header">Добро пожаловать в открытую сеть <br/>Общественной палата Российской Федерации. <font class="eng">Welcome to the open network of the Civic Chamber of the Russian Federation.</font></div> <?php if ($error) { echo '<div class="error">'.$error.'</div>';} else { ?> <div>Для получения доступа в интернет вам необходимо отправить SMS с кодом: <font class="code"><?php echo $code;?></font> на номер: <font class="num">+7 917 XXX-XX-XX.</font><br/><font class="eng">To access Internet, text this code <b><?php echo $code;?></b> to number <b>+7 917 XXX-XX-XX.</b></font></div> <div class="repeat">После отправки SMS нажмите на кнопку: <br/><font class="eng">After you've sent SMS with code, please click this button:</font></div> <a target="_self" href="<?php echo $url;?>" id="button" class="internet-disabled" onclick="return check();"> </a> <div class="repeat">Доставка и обработка вашего SMS может занять некоторое время. Пожалуйста, подождите несколько секунд.<br/><font class="eng">Please allow a minor delay in providing you access — delivery and processing of your SMS might take a few moments. Thank you for your patience.</font></div> <div class="sms">Стоимость SMS-сообщений тарифицируется согласно вашему тарифному плану.<br/>Cost of SMS-messages is charged according to your tariff plan.</div> <div class="law">Согласно постановлению Правительства №758 от 31 июля 2014г. и №801 от 12 августа 2014 г. - все публичные WIFI сети обязаны производить идентификацию пользователей.<br/>We require our WiFi users to authenticate following the provisions of the Russian law, stated by enactments 758 of 31st July 2014 and 801 of 12th August 2014. </div> <?php } ?> </div> </body> </html>
nano /var/www/hotspot/connect.php
# mysql login params $mysql_host = ''; $mysql_db = ''; $mysql_login = ''; $mysql_password = ''; $sql_link = mysqli_connect($mysql_host, $mysql_login, $mysql_password, $mysql_db) or die(mysql_error()); function sql_query($sql, $unbuffered = false){ global $sql_link; $resource = $unbuffered ? mysqli_real_query($sql_link, $sql) : mysqli_query($sql_link, $sql); if (mysqli_errno($sql_link) === 1016) { if (preg_match("/'(\S*)\.MYD'\. \(errno\: 145\)/", mysqli_error($sql_link), $m)) { mysqli_unbuffered_query("REPAIR TABLE ".$m[1]); $resource = $unbuffered ? mysqli_unbuffered_query($sql_link, $sql) : mysqli_query($sql_link, $sql); } } return $resource; } function sql_getValue($sql, $unbuffered = false){ $resource = sql_query($sql, $unbuffered); $ret = false; if (is_resource($resource) || is_object($resource)) { $row = mysqli_fetch_row($resource); $ret = $row[0]; } return $ret; } function sql_getRows($sql, $use_key = false, $unbuffered = false){ $resource = sql_query($sql, $unbuffered); $ret = false; if (is_resource($resource) || is_object($resource)) { $row = true; while ($row) { $row = mysqli_fetch_array($resource, MYSQLI_ASSOC); if (!$row) continue; $_row = $row; if ($use_key) { if (isset($_row[$use_key])) { $link = &$ret[$_row[$use_key]]; $link = $_row; } } else { $link = &$ret[]; $link = (count($_row) == 1) ? array_shift($_row) : $_row; } } } return $ret; } function sql_getColumn($sql, $id_field = 'id', $unbuffered = false){ $resource = sql_query($sql, $unbuffered); $ret = false; if (is_resource($resource) || is_object($resource)) { $row = true; while ($row) { $row = mysqli_fetch_array($resource, MYSQLI_ASSOC); if (!$row) continue; $_row = $row; $id = $_row[$id_field]; unset($_row[$id_field]); $value = current($_row); $ret[$id] = $value; } } return $ret; } function sql_getRow($sql, $unbuffered = false){ $resource = sql_query($sql, $unbuffered); $ret = false; if (is_resource($resource) || is_object($resource)) { $ret = mysqli_fetch_assoc($resource); } return $ret; }
Ну а теперь, добавим в sudoers права для управления iptables из php
nano /etc/sudoers smsd ALL=(ALL) NOPASSWD: /sbin/ipset smsd ALL=(ALL) NOPASSWD: /sbin/iptables www-data ALL=(ALL) NOPASSWD: /sbin/ipset www-data ALL=(ALL) NOPASSWD: /sbin/iptables smsd ALL=(ALL) NOPASSWD: /usr/sbin/conntrack www-data ALL=(ALL) NOPASSWD: /usr/sbin/conntrack
На этом вроде всё. Система в работе уже месяц, полёт нормальный. Спасибо за внимание!
