Jak stworzyć Captive Portal dla swojej firmy za pomocą Raspberry Pi Pico W
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
URL | Wyzwalanie odpowiedzi |
www.msftconnecttest.com/ncsi.txt | 200 OK |
www.msftconnecttest.com/connecttest.txt | 200 OK |
www.msftconnecttest.com/redirect | Przekierowanie 302 (do portalu przechwytującego, np. index.html) |
Android 9, 10
URL | Wyzwalanie odpowiedzi |
connectivitycheck.gstatic.com/generate_204 | Przekierowanie 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
iOS 15
URL | Wyzwalanie odpowiedzi |
captive.apple.com/hotspot-detect.html | 200 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.
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!
Dobry zamiennik pirateboxa (choć bez funkcji czatu i przesyłania).
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.
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.
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?
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!
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.
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?
Nie, musisz użyć raspberry pi pico dla każdego ssid.