Настройка wifi авторизации через sms под ubuntu 16.04

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

image

Для начала расскажу, как у нас организована сеть. Если не вдаваться в подробности, то развешены точки доступа 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


Здесь все довольно банально:

  1. Создаем виртуальную машинку (2 ядра, 4 Гб памяти, 2 сетевых интерфейса, 30 Гб диск)
  2. Качаем последний дистрибутив, подключаем, ставим...
  3. Настраиваем сетевые интерфейсы, один смотрит в 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

На этом вроде всё. Система в работе уже месяц, полёт нормальный. Спасибо за внимание!
Поделиться публикацией

Похожие публикации

Комментарии 35

    0
    Спасибо!
    Очень полезная статья. Сами в прошлом году пытались настроить подобное, но не вышло.
      0
      я правильно понимаю что:
      — все авторизованные юзеры идут на transparent proxy, и пробуете заблокировать часть https-сайтов используя SNI (и подделку сертификата ведь в /etc/squid/squidCA.pem лежит сертификат легитимного subCA). а если не секрет — что таким образом блокируется и почему?
      — вы намеренно ломаете механизм определения «а не стоит ли у нас captive portal» Android'а(иначе зачем игры с gstatic.com?
        0
        На первый вопрос очень хорошо разжевано в статье , на которую и опирался при настройке squid. Подмены сертификата не происходит.
        Насчет gstatic.com, согласен, не стоит. Похоже осталось с тестирования. Если оставить if (strpos($url, 'gstatic.com')!==false) $url = 'http://www.domain.ru';
        то начинается последовательность редиректов, авторизация проходит, но выглядит не эстетично.
        0
        в любом случае спасибо за подробное описание
          0
          >Согласно постановлению Правительства №758 от 31 июля 2014г. и №801 от 12 августа 2014 г.
          А есть у кого-нибудь ссылки на описание человеческим языком, что это такое, и чем это грозит? Потому что прочитал эти постановления, но всё равно ничего не понял :( Может какие статьи, или форумы?
          1) Если у меня дома Wi-Fi без пароля, я попадаю под закон?
          2) А кто это будет проверять? Что, уже есть «медиаполицейский», который ищет AP без пароля? Или какие другие контролирующие органы?
          3) Если в кафе Wi-Fi с паролём, но пароль выдают любому по запросу? Проверочные органы будут совершать «контрольную закупку» пароля?
          4) А если назвать точку доступа AndroidAP и говорить, что это не я, это кто-то с телефона интернет шарит?
          5) А если я приду во время проверки (см пункт 3) в офис к компании «ВЕКТОР», и подниму там мобильную точку доступа ООО_VECTOR_FREE, их оштрафуют?
            0
            Зачем кого то штрафовать. Вот если товарищ майор получит команду, выяснить — кто это с ип X.X.X.X написал плохое сообщение — то товарищ майор найдет владельца этого ип и назначит виноватым. И ваши отмазки — это кто то с моей АП написал, потому что там пароля нет — никого интересовать не будут. А в случае смс авторизации у владельцев кафе есть хоть какой то шанс отвести вопросы от себя, сославшись на то, что в это время вот владелец вот этого телефона сидел у нас на фривифи ;)
              0
              У нас так и начало происходить, начали сыпаться запросы. Вообще, есть маленькая тонкость. По закону, это необходимо делать провайдерам, а не организациям, которые используют. Но предоставляя доступ в интернет, посредством своей точки доступа, мы фактически, делать это не можем, так как не обладаем лицензией на предоставление телематических услуг.
                0
                Провайдер скажет, кафе такое-то, на этом роль провайдера заканчивается, а дальше владелец кафе уже заинтересован перевести стрелки, чтоб не отвечать за действия анонимусов. К тому же лицензия на оказание телематических услуг НЕ требуется, если услуга оказывается безвозмездно.
                  0
                  > начали сыпаться запросы.
                  От кого? Что было в запросах?
                    0
                    управление специальных технических мероприятий
                      0
                      А подробнее? Что хотели?
                        0
                        В рамках какого-либо запроса, кто с такого адреса тогда-то в такое-то время ходил куда-то.
              0
              непонятно… Вы так старательно выпиливаете отовсюду IPv6, а потом в конфиге нжиникса
              "
              listen [::]:80 default_server;
              listen [::]:443 ssl default_server;
              "
              Зачем?
                –1
                принимаю
                +3
                >Настройка фаервола iptables
                так как в нашей задаче, нам необходимо, чтобы сохранялись и таблицы ipset, то немного правим следующий файл:
                nano /usr/share/netfilter-persistent/plugins.d/15-ip4tables

                Лучше создать отдельный плагин, назвав его 20-ipset. В таком случае:
                1. Можно не переживать, что при обновлении пакета случайно перезатрут/перепишут 15-ip4tables
                2. Можно будет отдельно выполнять load / start / flush правил независимо от iptables
                  +1
                  Заметил, неточность.
                  Конечно же надо грузить ipset правила до iptables, поэтому файл надо назвать не 20-ipset, а к примеру 14-ipset.

                  Быстренько набросал скрипт: http://pastebin.com/ixwzB6fJ
                  +4
                  if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
                  	$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
                  } 
                  if (empty($ip)) $ip = $_SERVER['REMOTE_ADDR'];
                  
                  //определяем мак адрес
                  $mac = trim(shell_exec("arp -a ".$ip." | awk '{print $4}'"));
                  


                  Не рекомендовал бы так делать, потому что результат при изменении заголовка на:
                  X-Forwarded-For: | rm -rf /*
                  может быть печальным.
                    0
                    Добавил проверку ip адреса регулярным выражением, а именно:
                    //проверяем правильность 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;
                    
                    0
                    Есть пара вопросов…
                    1) Зачем в этой схеме использовать прокси? Вы же реализовали всю логику на iptables? Только для красивых логов?
                    2) Зачем писать логи в БД? Ведь логи — это вещь, которую не надо активно изменять, вставлять посередине. Почему не в файл?
                    3) Почему решили ограничивать доступ неавторизованных пользователей через iptables, а не через squid?
                    4) Почему выбрали именно схему, когда пользователь отправляет sms, а не вы пользователю?
                      0
                      1) Потому что задача стоит «перевести стрелки» на виновника. Если брать логи iptables, то получим только ip адреса источника и назначения. Нам же интересно, на какие сайты ходил пользователь и что там делал.
                      2) Для быстрого поиска, проще и правильнее использовать базу данных
                      3) Все-таки для каждой задачи, правильнее использовать инструмент для нее предназначенный. Squid это прокси, iptables фаервол.
                      4) Цена вопроса. Входящие смс бесплатные.
                        0
                        Однако в вашей схеме возникнут проблемы, когда решение нужно масштабировать на несколько офисов. В каждом из них придется держать отдельный такой сервер с iptables.
                      0
                      Не нашел ответа почему вы преднамеренно используете php 5.6 вместо 7?
                        +1
                        Так как когда-то программил на php 3,4,5, а разбираться с 7 и изучать отличия не было времени. Не могу сказать ничего плохого о php7, но могу много хорошего о php5…
                        0
                        У нас 10 залов для мероприятий (от 30 до 400 человек), а в день в среднем проходит от 4 до 12, плюс постоянная текучка народа и капризные пользователи.


                        Авторизация через смс выгодна обоим сторонам если имеется договоренность с оператором(ами), это вид авторизации реклама операторам сотовой связи
                          0
                          Всё это зело интересно, но как по мне это сизифов труд. В случае обращения «органов», «подозреваемый» может запросто сказать «логи подделаны, я не ходил в тырнет» или даже «меня там не было, это подстава».
                            +1
                            Задача не посадить подозреваемого, а не попасть под раздачу самим.
                              +1
                              Я к тому, что этого может оказаться недостаточно. Следует проконсультироваться с юристом. Возможно, без чего-то типа журнала подключений под роспись, эта система окажется юридически ничтожна и всё равно попадёте под раздачу, например, если окажется что найти «подозреваемого» по вашим данным не удаётся (неизвестный/незарегистрированный номер, подменённый МАС-адрес), то на вас же и повесят «подделка логов для ухода от ответственности» или как-то так. Это не сертифицированная железка типа СОРМа, которая как-то защищена от вмешательства с вашей стороны. Один ручной update блаблабла set ляляля where тополя, и вы сами не сможете сказать — было ли это вмешательство, например, злобными хакерами которые кого-то решили подставить (включая вас самих) или всё чисто.
                                0
                                В Украине в библиотеках, в которых предоставляется бесплатный доступ к Wi-Fi, записывают паспортные данные, а потом только дают пароль. Но полученные данные никак не связываются с устройством (или я не заметил).
                                На мой взгляд, — если госучреждение использует такую схему, то можно и всем. Но есть «но» — нужны паспортные данные или данные иного документа, удостоверяющего личность пользователя.
                                  0
                                  Хороший вопрос. В наших реалиях это зависит не столько от буквы закона, сколько от принятой в полиции практики его применения. Кто-нибудь сталкивался с запросами правоохранительных органов про бесплатный Wi-Fi?
                              +4
                              Пожалуйста, вычитывайте тексты для пользователей. Это традиционная беда у программистов, в результате рождаются толковые, но страхолюдные продукты :(

                              Для получения доступа в интернет, Вам необходимо c Вашего телефона отправить смс с кодом

                              Для получения доступа в интернет вам необходимо отправить SMS с кодом

                              To get access to the Internet, you need to send SMS with code to number

                              To access Internet, text this code: XXX to number YYY

                              Если Вы уже отправили смс с кодом, то нажмите на кнопку:

                              После отправки SMS нажмите на кнопку

                              If you have to send SMS with the code, then click on the button

                              After you've sent SMS with code, please click this button

                              Задержка предоставления доступа в интернет зависит от скорости доставки нам Вашего смс сообщения.

                              Доставка и обработка вашего SMS может занять некоторое время. Пожалуйста, выждите несколько секунд.

                              Delayed access to the Internet depends on the speed of delivery of SMS messages to us.

                              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.

                              According to the decree №758 of the Government dated 31 July 2014. and №801 from 12 August 2014 — all public WIFI network required to make user authentication.

                              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.
                                0
                                Большое спасибо пользователю artemsafe, которые прошел все этапы, нашел ошибки и помог внести необходимые правки, чтобы статья стала еще более лучше, а именно:
                                1) Исправил ошибку в запросе: CREATE TABLE `access_log`…
                                2) При установки phpmyadmin требуется еще apt-get install php5.6-mbstring
                                3) Не хватало apt-get update при сборке squid
                                4) Собранные пакеты squid попадают в исходную директорию 3.5.19
                                5) Необходимость перевода USB устройства в режим модема, как и с помощью чего…
                                  0
                                  А так же спасибо bougakov на языковую составляющую.
                                  0
                                  Добавил таймер на странице хотспота, чтобы нельзя было нажать кнопку «Перейти в интернет» в течении 60 секунд.
                                  nano /var/www/hotspot/index.php
                                  

                                  #Добавляем стиль для отключенной ссылки
                                  <style type="text/css">
                                  .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);         
                                  }
                                  </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 } ?>
                                  #Исправляем строчку с сылкой
                                  <a target="_self" href="<?php echo $url;?>" id="button" class="internet-disabled" onclick="return check();"> </a>
                                  

                                    0
                                    Есть способ авторизации WiFi клиентов публичной сети по СМС через встроенный функционал контроллера Edimax APC500.



                                    Через некоторое время размещу статью с тестированием или просто с описанием по этому вопросу.
                                      0
                                      Приветствую! Занимаюсь настройкой подобной связки прозрачного прокси с авторизацией.
                                      Вопрос: какой смысл перенаправлять HTTPS запросы на локальный nginx, если браузер всё равно не откроет страницу локального сервера из-за несоответствия сертификатов?
                                      Есть ли всё таки какой-то способ перенаправлять HTTPS запросы неавторизованных пользователей на страницу авторизации?
                                      Спасибо

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое