Jak stworzyć Captive Portal dla swojej firmy za pomocą Raspberry Pi Pico W

raspberry pi pico w captive portal set up

Jeśli prowadzisz firmę, skonfigurowanie portalu captive może być ważnym narzędziem dla Twojej sieci. W tym artykule pokażę, jak utworzyć portal captive za pomocą Raspberry Pi Pico W.

Portal captive zapewnia bezpieczny sposób oferowania Wi-Fi gościom, klientom lub klientom. Wymaga on od użytkowników zalogowania się lub uwierzytelnienia, zanim będą mogli korzystać z Internetu.

Pomyśl, jak to działa na lotnisku lub w sieci kawiarni.

Portal captive pozwala zarówno kontrolować, jak i monitorować sieć. Zapewnia również możliwość rozszerzenia marki. Portal captive można spersonalizować za pomocą logo.

Do czego służy portal captive?

Po zalogowaniu się do urządzenia Pico W, które działa jako punkt dostępu, nie zostanie wyświetlona strona internetowa. Dzięki zaimplementowanemu portalowi captive, gdy sieć Wi-Fi połączy się z hotspotem, pojawi się strona internetowa.

Dzięki temu można pominąć etap łączenia się z siecią, a następnie przechodzenia do przeglądarki i ręcznego wpisywania adresu IP.

W tym momencie muszę przyznać, że Kevin McAleer za film, który posłużył za podstawę tego poradnika.

Stworzenie własnego portalu z Pico W to fantastyczna okazja. Portal captive jest nie tylko niezbędny dla sieci firmowej. A Raspberry Pi Pico W wynosi zaledwie kilka euro, więc jest to również niezwykle opłacalne rozwiązanie.

Cele tego samouczka

Samouczek Kevina pokazuje tylko, jak uruchomić portal captive na urządzeniu Apple.

Ten samouczek pójdzie dalej, wyjaśniając, jak uruchomić wyskakujący portal captive na urządzeniach z systemem Android, Windows i Apple.

Będziemy używać Phew autorstwa Pimoroni, która jest biblioteką dla serwera WWW Pico W. Jest trochę jak Express dla NodeJS.

Przetestowałem swój kod na czterech urządzeniach:

  • Apple iPhone 8 z systemem operacyjnym w wersji 15.4.1 ✔️
  • Tablet Amazon Fire z systemem Android 9 ✔️
  • Windows 10 PC ✔️
  • Google Pixel 6 z systemem Android 13 ✔️
  • Samsung Note 9 z Androidem 10 ❌

Kod zadziałał na wszystkich z wyjątkiem mojego Samsunga Note 9 i nie testowałem go na Linuksie.

Przypadki użycia?

To trochę trudne zadanie.

Początkowo chciałem stworzyć coś, co mogłoby kogoś zrickrollować, ale zdałem sobie sprawę, że nie mogę osadzić filmu z YouTube, ponieważ nie będzie połączenia z Internetem, ponieważ Pico W nie ma połączenia z Internetem.

Następnie chciałem stworzyć przenośną cyfrową wizytówkę, gdzie ludzie mogliby połączyć się z Pico W i zobaczyć kilka linków. Coś w rodzaju tych katalogów Instagram link-in-bio. Ponownie, bez internetu...

Przypuszczam, że jedną z największych zalet Pico W jest możliwość bezprzewodowego sterowania komponentami.

Na stronie Nasz mega-tutorial dotyczący komponentówMówiłem o tym, jak można uniknąć używania fizycznych przycisków i pokręteł do sterowania diodami LED, brzęczykami i serwomechanizmami, używając zamiast tego interfejsu internetowego. Jeśli zaimplementujesz je w swoim portalu przechwytującym, będziesz mógł łatwiej kontrolować swoje urządzenia, ponieważ nie będziesz musiał logować się do 192.168.4.1 za każdym razem, gdy chcesz dostać się do panelu sterowania.

Oczywiście chętnie dowiem się, co według Ciebie jest możliwe dzięki portalowi captive. Zostaw komentarz poniżej!

Jak uruchomić wyskakujące okienko

Gdy łączysz się z siecią bezprzewodową, urządzenia z systemem Windows, Android i Apple pingują różne strony internetowe.

Każdy z tych pingów wymaga odpowiedzi. Właściwa odpowiedź odblokowuje wyskakujące okienko. Oto jak przebiega rozmowa w zależności od systemu operacyjnego:

Microsoft Windows 10

MS: "Psst... jest /connecttest.txt tam?"

Pico W: "Tak, 200“.

MS: "OK, zabierz mnie do /redirect

Pico W: "Tak, 302przejdź do http://pico.wireless/ gdzie będziemy Ci służyć index.html“.

Amazon Fire Android 9

AMZ: "Psst.. gdzie jest /generate_204 tam?"

Pico W: "Domyślnie chciałem powiedzieć 204ale wiem, że tak naprawdę chcesz 302 przekierowanie do http://pico.wireless/ (która renderuje index.html, czyli stronę przechwytującą)"

Apple iPhone 8 z systemem iOS 15

iPhone: "Jestem fajny i w ogóle, więc po prostu szukam pliku /hotspot-detect.html

Pico W: "Tak, idź do http://pico.wireless/

iPhone: "Hmm, wydaje się zupełnie inne od tego, o co prosiłem, ale ufam ci, więc pójdę tam teraz".

Kod odpowiedzi 200: "OK", 204: "Brak zawartości", 302: "Znaleziono".

Jak widać, różne urządzenia proszą o różne trasy i różne strony internetowe. A jeśli odpowiesz poprawnie, uruchomią wyskakujące okienko.

Oto podsumowanie tego, co należy wysłać i odebrać:

Windows 10

URLWyzwalanie odpowiedzi
www.msftconnecttest.com/ncsi.txt200 OK
www.msftconnecttest.com/connecttest.txt200 OK
www.msftconnecttest.com/redirectPrzekierowanie 302 (do portalu przechwytującego, np. index.html)

Android 9, 10

URLWyzwalanie odpowiedzi
connectivitycheck.gstatic.com/generate_204Przekierowanie 302 (na stronę portalu captive)

Inne wersje Androida mogą wysyłać zapytania pod inne adresy URL. Wierzę, że nowsze wersje Androida będą miały /generate_204 jako rozwiązanie awaryjne.

Oto dwa zasoby dla starszych Androidów:

https://lemariva.com/blog/2017/11/white-hacking-wemos-captive-portal-using-micropython

https://enterprisenetworkingatlarge.wordpress.com/2018/04/21/captive-portal-detection-on-android-and-others-client-vendors-vs-ap-vendors/

iOS 15

URLWyzwalanie odpowiedzi
captive.apple.com/hotspot-detect.html200 OK (odpowiedź za pomocą strony internetowej)

Mój Samsung Note 9 z Androidem 10 był najtrudniejszy do złamania. Pozornie można było postępować zgodnie z typowymi wzorcami Androida, ale niestety nic nie działało!

Udało mi się uzyskać monit "Wymagane logowanie", ale dopiero po zmianie DNS na publiczny adres IP sieci LAN (adres IP spoza zakresu "10.0.0.0/8, 172.16.0.0/12 lub 192.168.0.0/16"). Zobacz ten komentarz na Stack Exchange.

Ale wykonanie powyższego zepsuło portal captive każdego innego urządzenia...

Biblioteka Pimoroni Phew dla portalu przechwytującego Pico W

Pimoroni's Phew Biblioteka sprawia, że o wiele łatwiej jest stworzyć portal captive, ponieważ wykonali oni całą ciężką pracę.

Najpierw należy pobrać bibliotekę. Ja użyłem wersji 0.0.3 który można pobrać tutaj.

Następnie rozpakuj pliki i prześlij je do folderu o nazwie uff na Pico W. Osobiście korzystałem z Thonny IDE i możesz Dowiedz się, jak przesyłać pliki tutaj.

Pod koniec samouczka powinieneś mieć katalog, który wygląda tak.

Zakodujmy wyskakujące okienko hotspotu!

Zacznę więc od main.py:

from phew import logging, server, access_point, dns
from phew.template import render_template
from phew.server import redirect

DOMAIN = "pico.wireless"  # This is the address that is shown on the Captive Portal


@server.route("/", methods=['GET'])
def index(request):
    """ Render the Index page"""
    if request.method == 'GET':
        logging.debug("Get request")
        return render_template("index.html")

# microsoft windows redirects
@server.route("/ncsi.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("ncsi.txt")
    return "", 200


@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("connecttest.txt")
    return "", 200


@server.route("/redirect", methods=["GET"])
def hotspot(request):
    print(request)
    print("****************ms redir*********************")
    return redirect(f"http://{DOMAIN}/", 302)

# android redirects
@server.route("/generate_204", methods=["GET"])
def hotspot(request):
    print(request)
    print("******generate_204********")
    return redirect(f"http://{DOMAIN}/", 302)

# apple redir
@server.route("/hotspot-detect.html", methods=["GET"])
def hotspot(request):
    print(request)
    """ Redirect to the Index Page """
    return render_template("index.html")


@server.catchall()
def catch_all(request):
    print("***************CATCHALL***********************\n" + str(request))
    return redirect("http://" + DOMAIN + "/")


# Set to Accesspoint mode
# Change this to whatever Wifi SSID you wish
ap = access_point("Pico W Captive")
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# # Catch all requests and reroute them
dns.run_catchall(ip)
server.run()                            # Run the server
logging.info("Webserver Started")

Aby było jasne, zaadaptowałem ten kod od Kevina McAleera i zmieniłem go do naszych celów. Jeśli chcesz obejrzeć szczegółowe wyjaśnienie Kevina, jak to działa, obejrzyj ten film na YouTube.

Pozwolę sobie jednak pokrótce omówić poszczególne sekcje.

Istnieją trzy sekcje z komentarzami "#android redirects", "#apple redir" i "# microsoft windows redirects". Sekcje te obsługują testy przeprowadzane przez każdy system operacyjny i odpowiadają właściwą odpowiedzią.

Na końcu odpowiedzi są przekierowywane do http://{DOMAIN}/, z wyjątkiem trasy Apple (ponieważ Kevin napisał to w ten sposób, a jeśli nie jest zepsute...).

Przekierowanie do DOMAIN, zadeklarowane jako "pico.wireless", dałoby nam mniej nieestetyczny adres URL.

Zamiast więc widzieć "www.msftconnecttest.com" na pasku adresu, zobaczymy "pico.wireless" na pasku adresu. Oczywiście jest to coś, o czym należy pamiętać w przypadku portalu wewnętrznego firmy.

Pimoroni Phew redukuje kod, który trzeba napisać

Piękną rzeczą w Phew jest to, że piszesz znacznie mniej kodu, niż gdybyś pisał go od zera.

Na przykład, jeśli chcesz uruchomić SoftAP na Pico W, napiszesz kod, który wygląda mniej więcej tak:

import network
# start up network in access point mode
wlan = network.WLAN(network.AP_IF)
wlan.config(essid=ssid)
if password:
    wlan.config(password=password)
else:
    wlan.config(security=0)  # disable password
wlan.active(True)
return wlan

Z Pimoroni's Phew, twoje obciążenie jest zredukowane do:

ap = access_point("Pico W Captive")

Moim zdaniem najlepszą częścią jest dns.run_catchall() która uruchamia mnóstwo ważnego, ale skomplikowanego kodu:

import uasyncio, usocket
from . import logging

async def _handler(socket, ip_address):
  while True:
    try:
      yield uasyncio.core._io_queue.queue_read(socket)
      request, client = socket.recvfrom(256)
      response = request[:2] # request id
      response += b"\x81\x80" # response flags
      response += request[4:6] + request[4:6] # qd/an count
      response += b"\x00\x00\x00\x00" # ns/ar count
      response += request[12:] # origional request body
      response += b"\xC0\x0C" # pointer to domain name at byte 12
      response += b"\x00\x01\x00\x01" # type and class (A record / IN class)
      response += b"\x00\x00\x00\x3C" # time to live 60 seconds
      response += b"\x00\x04" # response length (4 bytes = 1 ipv4 address)
      response += bytes(map(int, ip_address.split("."))) # ip address parts
      socket.sendto(response, client)
    except Exception as e:
      logging.error(e)

def run_catchall(ip_address, port=53):
  logging.info("> starting catch all dns server on port {}".format(port))

  _socket = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)
  _socket.setblocking(False)
  _socket.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
  _socket.bind(usocket.getaddrinfo(ip_address, port, 0, usocket.SOCK_DGRAM)[0][-1])

  loop = uasyncio.get_event_loop()
  loop.create_task(_handler(_socket, ip_address))

Phew ułatwia również pisanie tras. Wszystko, co musisz zrobić, to napisać coś takiego:

@server.route("/[your_route_here]", methods=["GET"])
def your_function_here(request):
  pass

@server.catchall()
def catchall(request):
  pass

Jak widać powyżej, tworzenie trasy jest bardzo proste. Wszystko, co musisz zrobić, to użyć @server.routei przekazać trasę oraz metody. Następnie zdefiniuj funkcję poniżej za pomocą żądanie parametr.

Wreszcie, jest @server.catchall() która obsługuje wszystkie trasy, które nie zostały przypisane.

Dzięki temu jest to bardzo łatwe!

Odwiedź repozytorium Phew na Githubie tutaj.

index.html

To naprawdę prosty dowód słuszności koncepcji index.html który emituje <h1> "Pico W Captive Portal".

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Pico W Captive Portal</title>
  </head>
  <body>
    <h1>Pico W Captive Portal</h1>
  </body>
</html>

Wniosek

A więc to wszystko. To wszystko, co musisz wiedzieć, aby skonfigurować portal captive na Pico W dla swojej firmy.

Jeśli masz jakieś pytania, daj nam znać w komentarzach poniżej!

Komentarzy: 8

  1. cinos styczeń 8, 2023 o 4:11 pm

    Dobry zamiennik pirateboxa (choć bez funkcji czatu i przesyłania).

  2. OkinKun marzec 31, 2023 o 5:07 pm

    To jest dokładnie to, czego szukałem!
    Większość rzeczy działa, jednak strona nie wyskakuje sama, a zamiast tego widzę błąd:

    2023-03-31 12:02:35 [info / 160kB] > GET /generate_204 (302 Found) [236ms]
    Wyjątek zadania nie został pobrany
    przyszłość: coro=
    Traceback (ostatnie ostatnie wywołanie):
    Plik "uasyncio/core.py", linia 1, in run_until_complete
    Plik "phew/server.py", linia 242, in _handle_request
    Plik "phew/server.py", linia 161, in _parse_headers
    ValueError: potrzeba więcej niż 1 wartości do rozpakowania

    Zastanawiam się, czy może ma to coś wspólnego z tym, że mój stary telefon wciąż ma Androida 6.

  3. Dingleberry czerwiec 21, 2023 o 10:57 pm

    Jak można edytować ten kod, aby zawierał kod HTML wewnątrz programu? Próbowałem i nie zadziałało.

    Uważam, że przebieg programu jest bardzo zagmatwany.

    • Adam Bobeck czerwiec 26, 2023 o 2:51 pm

      Cześć! Chętnie pomogę! Czy mógłbyś opisać swój problem bardziej szczegółowo i powiedzieć mi, jakiego urządzenia używasz do portalu captive?

  4. NewbiePicoWHacker październik 1, 2023 o 3:36 pm

    Siemanko! Próbuję uruchomić to na Pico W. AP uruchamia się, DNS uruchamia się, serwer WWW albo nigdy się nie uruchamia, albo uruchamia się bardzo długo (kilka minut). Czy masz jakieś pomysły / wskazówki / sugestie, dlaczego? Dzięki!

  5. Prithwiraj Bose listopad 5, 2023 o 3:43 pm

    Czy możesz mi pomóc zrozumieć, która linia kodu wymusza/automatycznie otwiera captive portal w przeglądarce klienta po udanym połączeniu z hotspotem? Wydaje się, że nic nie otwiera się automatycznie. Łączę się z mojego laptopa.

  6. Peter listopad 24, 2023 o 8:13 pm

    Dzięki za dobry opis.

    Chciałbym dodać drugi lub nawet trzeci SSID do tego samego AP. Czy istnieje sposób, aby to zrobić za pomocą Phew?

    Jakieś przemyślenia?

    • Toby maj 28, 2024 o 5:13 pm

      Nie, musisz użyć raspberry pi pico dla każdego ssid.

Pozostaw komentarz