Портал авторизации с использованием nginx, hostapd, nftables, dnsmasq

Вопрос или проблема

Я пытаюсь создать captive портал с помощью nginx, hostapd, nftables, dnsmasq и python-flask.

У меня есть две основные проблемы

  1. На Android не появляется всплывающее окно, но на Iphone/OSX появляется.
  2. Я не уверен, как перенаправить пользователя после подключения. У меня есть команда nftables, но для этого нужен IP-адрес. Поскольку nginx перенаправляет с порта 80 на 8080 (python приложение), я не знаю, как получить это.

Вот nginx.conf

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;

        if ($request_method !~ ^(GET|HEAD|POST)$) { return 444; }

        # Handle iOS
        if ($http_user_agent ~* (CaptiveNetworkSupport) ) {
            return 302 http://go.portal;
        }

        # Handle Android captive portal detection
        location = /generate_204 {
            return 302 http://go.portal;
        }

        location = /gen_204 {
            return 302 http://go.portal;
        }

        # Default redirect for any unexpected requests to trigger captive portal
        # sign in screen on device.
        location / {
            return 302 http://go.portal;
        }
    }

    server {
        listen 80;
        listen [::]:80;
        server_name go.portal;

        # Only allow GET, HEAD, POST
        if ($request_method !~ ^(GET|HEAD|POST)$) { return 444; }

        root /var/www;

        index index.html;

        location /api/ {
            proxy_pass http://127.0.0.1:8080/api/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        location / {
            try_files $uri $uri/ =404;
        }

        # Redirect these errors to the home page.
        error_page 401 403 404 =200 /index.html;
    }
}

dnsmasq.conf

listen-address=192.168.2.1
no-hosts
# log-queries
log-facility=/var/log/dnsmasq.log
dhcp-range=192.168.2.2,192.168.2.254,72h
dhcp-option=option:router,192.168.2.1
dhcp-authoritative
dhcp-option=114,http://go.portal/index.html

# Resolve captive portal check domains to a "fake" external IP
address=/connectivitycheck.gstatic.com/10.45.12.1
address=/connectivitycheck.android.com/10.45.12.1
address=/clients3.google.com/10.45.12.1
address=/clients.l.google.com/10.45.12.1
address=/play.googleapis.com/10.45.12.1

# Resolve everything to the portal's IP address.
address=/#/192.168.2.1

Вот bash, который запускает всё.

INET_NIC=$(cat /run/inet_nic 2>/dev/null) || { echo "Connect to WiFi first"; exit 1; }
AP_NIC=$(cat /run/ap_nic 2>/dev/null) || { echo "Create AP first"; exit 1; }

echo 1 > /proc/sys/net/ipv4/ip_forward

nft flush ruleset

# Set up the filter table (Mode 1)
nft add table ip filter
nft add chain ip filter input  '{ type filter hook input priority 0; policy accept; }'
nft add chain ip filter forward '{ type filter hook forward priority 0; policy accept; }'
nft add chain ip filter output '{ type filter hook output priority 0; policy accept; }'

# Set up the NAT table and chain for masquerading (Mode 2)
nft add table ip nat
nft add chain ip nat postrouting '{ type nat hook postrouting priority 100; }'

kill -9 $(pidof dnsmasq) 2>/dev/null
dnsmasq -C /etc/dnsmasq.conf -d 2>&1 > $LOG_F &

kill -9 $(pidof nginx) 2>/dev/null
mkdir /var/log/nginx 2>/dev/null
nginx &

kill -9 $(pidof evil_portal) 2>/dev/null
ip link set lo up
/usr/bin/evil_portal &

И вот команда, которую я бы ввёл, когда пользователь принимает условия.

nft add rule ip nat postrouting oifname wlan1 ip saddr 192.168.2.217 masquerade

Я не буду делиться python/html кодом, так как это всё работает отлично. В основном я получаю нажатие кнопки пользователем, и моя функция Python вызывает это. Но Python сообщает мне, что IP — 127.0.0.1, потому что nginx перенаправляет трафик с порта 80 на 8080

Спасибо 🙂

Относительно проблемы 2:

Но Python сообщает мне, что IP — 127.0.0.1, потому что nginx перенаправляет трафик с порта 80 на 8080

Я предполагаю, что вы получаете 127.0.0.1 из подключенного сокета, верно? Но вам действительно нужен IP-адрес клиента. Согласно вашему конфигу nginx, вы должны быть в состоянии получить его из заголовка перенаправленного HTTP-сессии X-Real-IP.

Ответ или решение

Для реализации captive portal с использованием nginx, hostapd, nftables, dnsmasq и python-flask, важно создать сеть, где подключенные пользователи будут перенаправляться на веб-интерфейс, позволяющий осуществлять авторизацию или принимать условия предоставления доступа.

Теория

При создании captive portal необходимо учитывать несколько ключевых элементов:

  • nginx: Используется для обработки HTTP-запросов, создания редиректов и проксирования запросов к Flask-приложению.
  • hostapd: Создает точку доступа Wi-Fi и регулирует доступ Wi-Fi клиентов.
  • nftables: Управляет сетевой обработкой и обеспечивает механизм NAT для перенаправления сетевого трафика.
  • dnsmasq: Используется для предоставления DHCP-услуг клиентам и перенаправления DNS-запросов для передачи клиентов на указанный веб-сервер.

Рассмотрение проблемы с Android

Одной из главных ваших задач является отображение captive portal на устройствах с Android, подобно тому, как это происходит на iPhone и macOS. Поп-ап, который вы ожидаете на Android, связан с особенностями проверки состояния интернета на устройстве через определенные URL. В данной конфигурации используется перенаправление специфичных для Android доменов на внутренний IP (10.45.12.1). Убедитесь, что все такие домены актуальны для последних Android-версий. Также проверьте, что ваше Android-устройство может отправлять неполные GET-запросы на стандартный портал, и эти запросы корректно обрабатываются сервером.

Пример: Схема применения NGINX

Ваш конфигурационный файл nginx в целом верно настроен для обработки запросов от captive portal. Однако, особое внимание следует уделить правильному обработчику для Android. Убедитесь, что все возможные вариации URL для проверки сети поддерживаются.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    if ($http_user_agent ~* (Android|CaptivePortal) ) {
        return 302 http://go.portal;
    }

    # Default redirect for any unexpected requests to trigger captive portal
    location / {
        return 302 http://go.portal;
    }
}

Пример: Реализация DHCP и DNS с Dnsmasq

Конфигурация dnsmasq должна корректно обслуживать запросы, распределять IP-адреса и экранировать все запросы на заданные домены. Пример вашей настройки выглядит подходяще, но проверьте актуальность всех доменных имен, используемых в Android для проверки соединения.

Применение: Решение проблемы с IP-адресами

Ваша задача по получению реального IP-адреса клиента связана с тем, что nginx проксирует запросы во Flask-приложение, и оно принимает их с IP 127.0.0.1. Чтобы извлечь реальный IP-адрес, передаваемый nginx, используйте заголовок HTTP X-Real-IP, как правило, он добавляется конфигурацией nginx и затем может быть извлечен во Flask:

from flask import request

@app.route('/your-endpoint', methods=['POST'])
def your_endpoint():
    real_ip = request.headers.get('X-Real-IP')
    if not real_ip:
        real_ip = request.remote_addr
    # Дальнейшая обработка

Практическая рекомендация

Понимание проблемы со специфичным поведением Android в captive portal может потребовать комплексного тестирования и отладки. Убедитесь, что сеть captive portal действительно доступна и корректно перенаправляет на всех устройствах. Это может потребовать изменения или дополнения к nginx-конфигурации, а также внесения правок в правила nftables для обеспечения правильной маршрутизации.

Заключение

Каждая часть системы captive portal (nginx, hostapd, dnsmasq, nftables, Flask) должна быть тщательно интегрирована и протестирована, чтобы обеспечить плавное и надежное функционирование. Отлаживайте как свой серверный код, так и сетевые конфигурации, чтобы идентифицировать и устранять узкие места. Внимательное тестирование на разных устройствах и платформах поможет гарантировать, что пользователи смогут легко подключаться и взаимодействовать с вашим порталом.

Оцените материал
Добавить комментарий

Капча загружается...